mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-14941 Timeouts on persistent statistics tables caused by MDEV-14511
MDEV-14511 tried to avoid some consistency problems related to InnoDB persistent statistics. The persistent statistics are being written by an InnoDB internal SQL interpreter that requires the InnoDB data dictionary cache to be locked. Before MDEV-14511, the statistics were written during DDL in separate transactions, which could unnecessarily reduce performance (each commit would require a redo log flush) and break atomicity, because the statistics would be updated separately from the dictionary transaction. However, because it is unacceptable to hold the InnoDB data dictionary cache locked while suspending the execution for waiting for a transactional lock (in the mysql.innodb_index_stats or mysql.innodb_table_stats tables) to be released, any lock conflict was immediately be reported as "lock wait timeout". To fix MDEV-14941, an attempt to reduce these lock conflicts by acquiring transactional locks on the user tables in both the statistics and DDL operations was made, but it would still not entirely prevent lock conflicts on the mysql.innodb_index_stats and mysql.innodb_table_stats tables. Fixing the remaining problems would require a change that is too intrusive for a GA release series, such as MariaDB 10.2. Thefefore, we revert the change MDEV-14511. To silence the MDEV-13201 assertion, we use the pre-existing flag trx_t::internal.
This commit is contained in:
@ -1,12 +0,0 @@
|
|||||||
call mtr.add_suppression("InnoDB: Cannot save (table|index) statistics for table `test`\\.`t1`.*: Persistent statistics do not exist");
|
|
||||||
CREATE TABLE t1 (a INT, KEY(a)) ENGINE=INNODB STATS_PERSISTENT=1;
|
|
||||||
SET @save_debug= @@SESSION.debug_dbug;
|
|
||||||
SET debug_dbug= '+d,stats_index_error';
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status Operation failed
|
|
||||||
SET debug_dbug= @save_debug;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
Table Op Msg_type Msg_text
|
|
||||||
test.t1 analyze status OK
|
|
||||||
DROP TABLE t1;
|
|
@ -1,13 +0,0 @@
|
|||||||
--source include/have_innodb.inc
|
|
||||||
--source include/have_debug.inc
|
|
||||||
|
|
||||||
call mtr.add_suppression("InnoDB: Cannot save (table|index) statistics for table `test`\\.`t1`.*: Persistent statistics do not exist");
|
|
||||||
|
|
||||||
CREATE TABLE t1 (a INT, KEY(a)) ENGINE=INNODB STATS_PERSISTENT=1;
|
|
||||||
SET @save_debug= @@SESSION.debug_dbug;
|
|
||||||
SET debug_dbug= '+d,stats_index_error';
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
SET debug_dbug= @save_debug;
|
|
||||||
ANALYZE TABLE t1;
|
|
||||||
|
|
||||||
DROP TABLE t1;
|
|
@ -57,5 +57,5 @@ SELECT table_name FROM mysql.innodb_index_stats
|
|||||||
WHERE table_name='innodb_stats_drop_locked';
|
WHERE table_name='innodb_stats_drop_locked';
|
||||||
|
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
call mtr.add_suppression("Unable to delete statistics for table test\\.innodb_stats_drop_locked: Lock wait");
|
call mtr.add_suppression("Unable to delete statistics for table test.innodb_stats_drop_locked: Lock wait timeout. They can be deleted later using DELETE FROM mysql.innodb_index_stats WHERE database_name");
|
||||||
--enable_query_log
|
--enable_query_log
|
||||||
|
@ -751,8 +751,6 @@ DECLARE_THREAD(btr_defragment_thread)(void*)
|
|||||||
buf_block_t* first_block;
|
buf_block_t* first_block;
|
||||||
buf_block_t* last_block;
|
buf_block_t* last_block;
|
||||||
|
|
||||||
trx_t* trx = trx_allocate_for_background();
|
|
||||||
|
|
||||||
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
|
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
|
||||||
ut_ad(btr_defragment_thread_active);
|
ut_ad(btr_defragment_thread_active);
|
||||||
|
|
||||||
@ -828,36 +826,31 @@ DECLARE_THREAD(btr_defragment_thread)(void*)
|
|||||||
/* Update the last_processed time of this index. */
|
/* Update the last_processed time of this index. */
|
||||||
item->last_processed = now;
|
item->last_processed = now;
|
||||||
} else {
|
} else {
|
||||||
|
dberr_t err = DB_SUCCESS;
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
/* Reaching the end of the index. */
|
/* Reaching the end of the index. */
|
||||||
dict_stats_empty_defrag_stats(index);
|
dict_stats_empty_defrag_stats(index);
|
||||||
trx->error_state = DB_SUCCESS;
|
err = dict_stats_save_defrag_stats(index);
|
||||||
ut_d(trx->persistent_stats = true);
|
|
||||||
++trx->will_lock;
|
|
||||||
dberr_t err = dict_stats_save_defrag_stats(index, trx);
|
|
||||||
if (err == DB_SUCCESS) {
|
|
||||||
err = dict_stats_save_defrag_summary(
|
|
||||||
index, trx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
trx_rollback_to_savepoint(trx, NULL);
|
|
||||||
ib::error() << "Saving defragmentation stats for table "
|
ib::error() << "Saving defragmentation stats for table "
|
||||||
<< index->table->name
|
<< index->table->name.m_name
|
||||||
<< " index " << index->name
|
<< " index " << index->name()
|
||||||
<< " failed with error "
|
<< " failed with error " << err;
|
||||||
<< ut_strerr(err);
|
} else {
|
||||||
} else if (trx->state != TRX_STATE_NOT_STARTED) {
|
err = dict_stats_save_defrag_summary(index);
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
ib::error() << "Saving defragmentation summary for table "
|
||||||
|
<< index->table->name.m_name
|
||||||
|
<< " index " << index->name()
|
||||||
|
<< " failed with error " << err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_d(trx->persistent_stats = false);
|
|
||||||
btr_defragment_remove_item(item);
|
btr_defragment_remove_item(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trx_free_for_background(trx);
|
|
||||||
|
|
||||||
btr_defragment_thread_active = false;
|
btr_defragment_thread_active = false;
|
||||||
os_thread_exit();
|
os_thread_exit();
|
||||||
OS_THREAD_DUMMY_RETURN;
|
OS_THREAD_DUMMY_RETURN;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2016, 2017, MariaDB Corporation.
|
Copyright (c) 2016, MariaDB Corporation. All Rights Reserved.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -29,7 +29,6 @@ Created 25/08/2016 Jan Lindström
|
|||||||
#include "dict0defrag_bg.h"
|
#include "dict0defrag_bg.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "srv0start.h"
|
#include "srv0start.h"
|
||||||
#include "trx0roll.h"
|
|
||||||
#include "ut0new.h"
|
#include "ut0new.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -202,18 +201,17 @@ dict_stats_defrag_pool_del(
|
|||||||
mutex_exit(&defrag_pool_mutex);
|
mutex_exit(&defrag_pool_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the first index that has been added for updating persistent defrag
|
/*****************************************************************//**
|
||||||
stats and eventually save its stats.
|
Get the first index that has been added for updating persistent defrag
|
||||||
@param[in,out] trx transaction that will be started and committed */
|
stats and eventually save its stats. */
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
dict_stats_process_entry_from_defrag_pool(trx_t* trx)
|
dict_stats_process_entry_from_defrag_pool()
|
||||||
{
|
{
|
||||||
table_id_t table_id;
|
table_id_t table_id;
|
||||||
index_id_t index_id;
|
index_id_t index_id;
|
||||||
|
|
||||||
ut_ad(!srv_read_only_mode);
|
ut_ad(!srv_read_only_mode);
|
||||||
ut_ad(trx->persistent_stats);
|
|
||||||
|
|
||||||
/* pop the first index from the auto defrag pool */
|
/* pop the first index from the auto defrag pool */
|
||||||
if (!dict_stats_defrag_pool_get(&table_id, &index_id)) {
|
if (!dict_stats_defrag_pool_get(&table_id, &index_id)) {
|
||||||
@ -242,64 +240,62 @@ dict_stats_process_entry_from_defrag_pool(trx_t* trx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
dict_stats_save_defrag_stats(index);
|
||||||
trx->error_state = DB_SUCCESS;
|
|
||||||
++trx->will_lock;
|
|
||||||
dberr_t err = dict_stats_save_defrag_stats(index, trx);
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
trx_rollback_to_savepoint(trx, NULL);
|
|
||||||
ib::error() << "Saving defragmentation status for table "
|
|
||||||
<< index->table->name
|
|
||||||
<< " index " << index->name
|
|
||||||
<< " failed " << err;
|
|
||||||
} else if (trx->state != TRX_STATE_NOT_STARTED) {
|
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
}
|
|
||||||
|
|
||||||
dict_table_close(table, FALSE, FALSE);
|
dict_table_close(table, FALSE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Process indexes that have been scheduled for defragmenting.
|
/*****************************************************************//**
|
||||||
@param[in,out] trx transaction that will be started and committed */
|
Get the first index that has been added for updating persistent defrag
|
||||||
|
stats and eventually save its stats. */
|
||||||
void
|
void
|
||||||
dict_defrag_process_entries_from_defrag_pool(trx_t* trx)
|
dict_defrag_process_entries_from_defrag_pool()
|
||||||
|
/*==========================================*/
|
||||||
{
|
{
|
||||||
while (defrag_pool->size() && !dict_stats_start_shutdown) {
|
while (defrag_pool->size() && !dict_stats_start_shutdown) {
|
||||||
dict_stats_process_entry_from_defrag_pool(trx);
|
dict_stats_process_entry_from_defrag_pool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Save defragmentation result.
|
/*********************************************************************//**
|
||||||
@param[in] index index that was defragmented
|
Save defragmentation result.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save_defrag_summary(dict_index_t* index, trx_t* trx)
|
dict_stats_save_defrag_summary(
|
||||||
|
/*============================*/
|
||||||
|
dict_index_t* index) /*!< in: index */
|
||||||
{
|
{
|
||||||
ut_ad(trx->persistent_stats);
|
dberr_t ret=DB_SUCCESS;
|
||||||
|
lint now = (lint) ut_time();
|
||||||
|
|
||||||
if (dict_index_is_ibuf(index)) {
|
if (dict_index_is_ibuf(index)) {
|
||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dict_stats_save_index_stat(index, ut_time(), "n_pages_freed",
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
index->stat_defrag_n_pages_freed,
|
mutex_enter(&dict_sys->mutex);
|
||||||
NULL,
|
|
||||||
"Number of pages freed during"
|
ret = dict_stats_save_index_stat(index, now, "n_pages_freed",
|
||||||
" last defragmentation run.",
|
index->stat_defrag_n_pages_freed,
|
||||||
trx);
|
NULL,
|
||||||
|
"Number of pages freed during"
|
||||||
|
" last defragmentation run.",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
mutex_exit(&dict_sys->mutex);
|
||||||
|
rw_lock_x_unlock(dict_operation_lock);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Save defragmentation stats for a given index.
|
/*********************************************************************//**
|
||||||
@param[in] index index that is being defragmented
|
Save defragmentation stats for a given index.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save_defrag_stats(dict_index_t* index, trx_t* trx)
|
dict_stats_save_defrag_stats(
|
||||||
|
/*============================*/
|
||||||
|
dict_index_t* index) /*!< in: index */
|
||||||
{
|
{
|
||||||
ut_ad(trx->error_state == DB_SUCCESS);
|
dberr_t ret;
|
||||||
ut_ad(trx->persistent_stats);
|
|
||||||
|
|
||||||
if (dict_index_is_ibuf(index)) {
|
if (dict_index_is_ibuf(index)) {
|
||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
@ -309,6 +305,7 @@ dict_stats_save_defrag_stats(dict_index_t* index, trx_t* trx)
|
|||||||
return dict_stats_report_error(index->table, true);
|
return dict_stats_report_error(index->table, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lint now = (lint) ut_time();
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
ulint n_leaf_pages;
|
ulint n_leaf_pages;
|
||||||
ulint n_leaf_reserved;
|
ulint n_leaf_reserved;
|
||||||
@ -325,33 +322,40 @@ dict_stats_save_defrag_stats(dict_index_t* index, trx_t* trx)
|
|||||||
return DB_SUCCESS;
|
return DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
ib_time_t now = ut_time();
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
dberr_t err = dict_stats_save_index_stat(
|
|
||||||
index, now, "n_page_split",
|
mutex_enter(&dict_sys->mutex);
|
||||||
index->stat_defrag_n_page_split,
|
ret = dict_stats_save_index_stat(index, now, "n_page_split",
|
||||||
|
index->stat_defrag_n_page_split,
|
||||||
|
NULL,
|
||||||
|
"Number of new page splits on leaves"
|
||||||
|
" since last defragmentation.",
|
||||||
|
NULL);
|
||||||
|
if (ret != DB_SUCCESS) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = dict_stats_save_index_stat(
|
||||||
|
index, now, "n_leaf_pages_defrag",
|
||||||
|
n_leaf_pages,
|
||||||
NULL,
|
NULL,
|
||||||
"Number of new page splits on leaves"
|
"Number of leaf pages when this stat is saved to disk",
|
||||||
" since last defragmentation.",
|
NULL);
|
||||||
trx);
|
if (ret != DB_SUCCESS) {
|
||||||
if (err == DB_SUCCESS) {
|
goto end;
|
||||||
err = dict_stats_save_index_stat(
|
|
||||||
index, now, "n_leaf_pages_defrag",
|
|
||||||
n_leaf_pages,
|
|
||||||
NULL,
|
|
||||||
"Number of leaf pages when this stat is saved to disk",
|
|
||||||
trx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == DB_SUCCESS) {
|
ret = dict_stats_save_index_stat(
|
||||||
err = dict_stats_save_index_stat(
|
index, now, "n_leaf_pages_reserved",
|
||||||
index, now, "n_leaf_pages_reserved",
|
n_leaf_reserved,
|
||||||
n_leaf_reserved,
|
NULL,
|
||||||
NULL,
|
"Number of pages reserved for this index leaves when this stat "
|
||||||
"Number of pages reserved for this "
|
"is saved to disk",
|
||||||
"index leaves when this stat "
|
NULL);
|
||||||
"is saved to disk",
|
|
||||||
trx);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
end:
|
||||||
|
mutex_exit(&dict_sys->mutex);
|
||||||
|
rw_lock_x_unlock(dict_operation_lock);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2009, 2017, 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.
|
Copyright (c) 2015, 2018, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -276,7 +276,9 @@ This function will free the pinfo object.
|
|||||||
@param[in,out] pinfo pinfo to pass to que_eval_sql() must already
|
@param[in,out] pinfo pinfo to pass to que_eval_sql() must already
|
||||||
have any literals bound to it
|
have any literals bound to it
|
||||||
@param[in] sql SQL string to execute
|
@param[in] sql SQL string to execute
|
||||||
@param[in,out] trx transaction
|
@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.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
static
|
static
|
||||||
dberr_t
|
dberr_t
|
||||||
@ -286,12 +288,53 @@ dict_stats_exec_sql(
|
|||||||
trx_t* trx)
|
trx_t* trx)
|
||||||
{
|
{
|
||||||
dberr_t err;
|
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 */
|
err = que_eval_sql(pinfo, sql, FALSE, trx); /* pinfo is freed here */
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("stats_index_error",
|
DBUG_EXECUTE_IF("stats_index_error",
|
||||||
|
if (!trx_started) {
|
||||||
err = DB_STATS_DO_NOT_EXIST;
|
err = DB_STATS_DO_NOT_EXIST;
|
||||||
trx->error_state = 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);
|
||||||
|
}
|
||||||
|
|
||||||
return(err);
|
return(err);
|
||||||
}
|
}
|
||||||
@ -500,12 +543,16 @@ dict_stats_empty_index(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reset the table and index statsistics, corresponding to an empty table.
|
/*********************************************************************//**
|
||||||
@param[in,out] table table whose statistics are to be reset
|
Write all zeros (or 1 where it makes sense) into a table and its indexes'
|
||||||
@param[in] empty_defrag_stats whether to empty the defrag statistics
|
statistics members. The resulting stats correspond to an empty table. */
|
||||||
*/
|
static
|
||||||
void
|
void
|
||||||
dict_stats_empty_table(dict_table_t* table, bool empty_defrag_stats)
|
dict_stats_empty_table(
|
||||||
|
/*===================*/
|
||||||
|
dict_table_t* table, /*!< in/out: table */
|
||||||
|
bool empty_defrag_stats)
|
||||||
|
/*!< in: whether to empty defrag stats */
|
||||||
{
|
{
|
||||||
/* Zero the stats members */
|
/* Zero the stats members */
|
||||||
|
|
||||||
@ -2251,7 +2298,9 @@ storage.
|
|||||||
@param[in] stat_value value of the stat
|
@param[in] stat_value value of the stat
|
||||||
@param[in] sample_size n pages sampled or NULL
|
@param[in] sample_size n pages sampled or NULL
|
||||||
@param[in] stat_description description of the stat
|
@param[in] stat_description description of the stat
|
||||||
@param[in,out] trx transaction
|
@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.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save_index_stat(
|
dict_stats_save_index_stat(
|
||||||
@ -2268,7 +2317,9 @@ dict_stats_save_index_stat(
|
|||||||
char db_utf8[MAX_DB_UTF8_LEN];
|
char db_utf8[MAX_DB_UTF8_LEN];
|
||||||
char table_utf8[MAX_TABLE_UTF8_LEN];
|
char table_utf8[MAX_TABLE_UTF8_LEN];
|
||||||
|
|
||||||
ut_ad(trx->persistent_stats || trx->in_mysql_trx_list);
|
ut_ad(!trx || trx->internal || trx->in_mysql_trx_list);
|
||||||
|
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
|
||||||
|
ut_ad(mutex_own(&dict_sys->mutex));
|
||||||
|
|
||||||
dict_fs2utf8(index->table->name.m_name, db_utf8, sizeof(db_utf8),
|
dict_fs2utf8(index->table->name.m_name, db_utf8, sizeof(db_utf8),
|
||||||
table_utf8, sizeof(table_utf8));
|
table_utf8, sizeof(table_utf8));
|
||||||
@ -2294,8 +2345,6 @@ dict_stats_save_index_stat(
|
|||||||
pars_info_add_str_literal(pinfo, "stat_description",
|
pars_info_add_str_literal(pinfo, "stat_description",
|
||||||
stat_description);
|
stat_description);
|
||||||
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
|
||||||
|
|
||||||
ret = dict_stats_exec_sql(
|
ret = dict_stats_exec_sql(
|
||||||
pinfo,
|
pinfo,
|
||||||
"PROCEDURE INDEX_STATS_SAVE () IS\n"
|
"PROCEDURE INDEX_STATS_SAVE () IS\n"
|
||||||
@ -2322,8 +2371,6 @@ dict_stats_save_index_stat(
|
|||||||
");\n"
|
");\n"
|
||||||
"END;", trx);
|
"END;", trx);
|
||||||
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
if (ret != DB_SUCCESS) {
|
||||||
if (innodb_index_stats_not_found == false &&
|
if (innodb_index_stats_not_found == false &&
|
||||||
index->stats_error_printed == false) {
|
index->stats_error_printed == false) {
|
||||||
@ -2376,7 +2423,6 @@ dict_stats_report_error(dict_table_t* table, bool defragment)
|
|||||||
|
|
||||||
/** Save the table's statistics into the persistent statistics storage.
|
/** Save the table's statistics into the persistent statistics storage.
|
||||||
@param[in] table_orig table whose stats to save
|
@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
|
@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
|
that are not equal to it will not be saved, if NULL, then all indexes' stats
|
||||||
are saved
|
are saved
|
||||||
@ -2385,8 +2431,7 @@ static
|
|||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save(
|
dict_stats_save(
|
||||||
dict_table_t* table_orig,
|
dict_table_t* table_orig,
|
||||||
trx_t* trx,
|
const index_id_t* only_for_index)
|
||||||
const index_id_t* only_for_index = NULL)
|
|
||||||
{
|
{
|
||||||
pars_info_t* pinfo;
|
pars_info_t* pinfo;
|
||||||
ib_time_t now;
|
ib_time_t now;
|
||||||
@ -2395,10 +2440,11 @@ dict_stats_save(
|
|||||||
char db_utf8[MAX_DB_UTF8_LEN];
|
char db_utf8[MAX_DB_UTF8_LEN];
|
||||||
char table_utf8[MAX_TABLE_UTF8_LEN];
|
char table_utf8[MAX_TABLE_UTF8_LEN];
|
||||||
|
|
||||||
ut_ad(trx->persistent_stats || trx->in_mysql_trx_list);
|
if (high_level_read_only) {
|
||||||
|
return DB_READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
if (table_orig->is_readable()) {
|
if (!table_orig->is_readable()) {
|
||||||
} else {
|
|
||||||
return (dict_stats_report_error(table_orig));
|
return (dict_stats_report_error(table_orig));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2407,8 +2453,9 @@ dict_stats_save(
|
|||||||
dict_fs2utf8(table->name.m_name, db_utf8, sizeof(db_utf8),
|
dict_fs2utf8(table->name.m_name, db_utf8, sizeof(db_utf8),
|
||||||
table_utf8, sizeof(table_utf8));
|
table_utf8, sizeof(table_utf8));
|
||||||
|
|
||||||
|
|
||||||
now = ut_time();
|
now = ut_time();
|
||||||
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
|
mutex_enter(&dict_sys->mutex);
|
||||||
|
|
||||||
pinfo = pars_info_create();
|
pinfo = pars_info_create();
|
||||||
|
|
||||||
@ -2421,8 +2468,6 @@ dict_stats_save(
|
|||||||
pars_info_add_ull_literal(pinfo, "sum_of_other_index_sizes",
|
pars_info_add_ull_literal(pinfo, "sum_of_other_index_sizes",
|
||||||
table->stat_sum_of_other_index_sizes);
|
table->stat_sum_of_other_index_sizes);
|
||||||
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
|
||||||
|
|
||||||
ret = dict_stats_exec_sql(
|
ret = dict_stats_exec_sql(
|
||||||
pinfo,
|
pinfo,
|
||||||
"PROCEDURE TABLE_STATS_SAVE () IS\n"
|
"PROCEDURE TABLE_STATS_SAVE () IS\n"
|
||||||
@ -2443,18 +2488,28 @@ dict_stats_save(
|
|||||||
":clustered_index_size,\n"
|
":clustered_index_size,\n"
|
||||||
":sum_of_other_index_sizes\n"
|
":sum_of_other_index_sizes\n"
|
||||||
");\n"
|
");\n"
|
||||||
"END;", trx);
|
"END;", NULL);
|
||||||
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
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();
|
||||||
|
trx_start_internal(trx);
|
||||||
|
|
||||||
|
dict_index_t* index;
|
||||||
index_map_t indexes(
|
index_map_t indexes(
|
||||||
(ut_strcmp_functor()),
|
(ut_strcmp_functor()),
|
||||||
index_map_t_allocator(mem_key_dict_stats_index_map_t));
|
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
|
/* Below we do all the modifications in innodb_index_stats in a single
|
||||||
transaction for performance reasons. Modifying more than one row in a
|
transaction for performance reasons. Modifying more than one row in a
|
||||||
single transaction may deadlock with other transactions if they
|
single transaction may deadlock with other transactions if they
|
||||||
@ -2467,17 +2522,18 @@ dict_stats_save(
|
|||||||
stat_name). This is why below we sort the indexes by name and then
|
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 each index, do the mods ordered by stat_name. */
|
||||||
|
|
||||||
for (dict_index_t* index = dict_table_get_first_index(table);
|
for (index = dict_table_get_first_index(table);
|
||||||
index != NULL;
|
index != NULL;
|
||||||
index = dict_table_get_next_index(index)) {
|
index = dict_table_get_next_index(index)) {
|
||||||
|
|
||||||
indexes[index->name] = index;
|
indexes[index->name] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index_map_t::const_iterator it = indexes.begin();
|
index_map_t::const_iterator it;
|
||||||
it != indexes.end(); ++it) {
|
|
||||||
|
|
||||||
dict_index_t* index = it->second;
|
for (it = indexes.begin(); it != indexes.end(); ++it) {
|
||||||
|
|
||||||
|
index = it->second;
|
||||||
|
|
||||||
if (only_for_index != NULL && index->id != *only_for_index) {
|
if (only_for_index != NULL && index->id != *only_for_index) {
|
||||||
continue;
|
continue;
|
||||||
@ -2540,11 +2596,13 @@ dict_stats_save(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
trx_commit_for_mysql(trx);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
ib::error() << "Cannot save table statistics for table "
|
trx_free_for_background(trx);
|
||||||
<< table->name << ": " << ut_strerr(ret);
|
|
||||||
}
|
mutex_exit(&dict_sys->mutex);
|
||||||
|
rw_lock_x_unlock(dict_operation_lock);
|
||||||
|
|
||||||
dict_stats_snapshot_free(table);
|
dict_stats_snapshot_free(table);
|
||||||
|
|
||||||
@ -3042,13 +3100,12 @@ dict_stats_empty_defrag_modified_counter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculate index statistics.
|
/*********************************************************************//**
|
||||||
@param[in,out] index index tree
|
Fetches or calculates new estimates for index statistics. */
|
||||||
@param[in,out] trx transaction (for persistent statistics)
|
void
|
||||||
@return DB_SUCCESS or error code */
|
dict_stats_update_for_index(
|
||||||
UNIV_INTERN
|
/*========================*/
|
||||||
dberr_t
|
dict_index_t* index) /*!< in/out: index */
|
||||||
dict_stats_update_for_index(dict_index_t* index, trx_t* trx)
|
|
||||||
{
|
{
|
||||||
DBUG_ENTER("dict_stats_update_for_index");
|
DBUG_ENTER("dict_stats_update_for_index");
|
||||||
|
|
||||||
@ -3060,8 +3117,8 @@ dict_stats_update_for_index(dict_index_t* index, trx_t* trx)
|
|||||||
dict_table_stats_lock(index->table, RW_X_LATCH);
|
dict_table_stats_lock(index->table, RW_X_LATCH);
|
||||||
dict_stats_analyze_index(index);
|
dict_stats_analyze_index(index);
|
||||||
dict_table_stats_unlock(index->table, RW_X_LATCH);
|
dict_table_stats_unlock(index->table, RW_X_LATCH);
|
||||||
DBUG_RETURN(dict_stats_save(index->table, trx,
|
dict_stats_save(index->table, &index->id);
|
||||||
&index->id));
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
/* else */
|
/* else */
|
||||||
|
|
||||||
@ -3084,20 +3141,22 @@ dict_stats_update_for_index(dict_index_t* index, trx_t* trx)
|
|||||||
dict_stats_update_transient_for_index(index);
|
dict_stats_update_transient_for_index(index);
|
||||||
dict_table_stats_unlock(index->table, RW_X_LATCH);
|
dict_table_stats_unlock(index->table, RW_X_LATCH);
|
||||||
|
|
||||||
DBUG_RETURN(DB_SUCCESS);
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculate new estimates for table and index statistics.
|
/*********************************************************************//**
|
||||||
@param[in,out] table table
|
Calculates new estimates for table and index statistics. The statistics
|
||||||
@param[in] stats_upd_option how to update statistics
|
are used in query optimization.
|
||||||
@param[in,out] trx transaction
|
@return DB_SUCCESS or error code */
|
||||||
@return DB_* error code or DB_SUCCESS */
|
|
||||||
UNIV_INTERN
|
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_update(
|
dict_stats_update(
|
||||||
dict_table_t* table,
|
/*==============*/
|
||||||
dict_stats_upd_option_t stats_upd_option,
|
dict_table_t* table, /*!< in/out: table */
|
||||||
trx_t* trx)
|
dict_stats_upd_option_t stats_upd_option)
|
||||||
|
/*!< in: whether to (re) calc
|
||||||
|
the stats or to fetch them from
|
||||||
|
the persistent statistics
|
||||||
|
storage */
|
||||||
{
|
{
|
||||||
ut_ad(!mutex_own(&dict_sys->mutex));
|
ut_ad(!mutex_own(&dict_sys->mutex));
|
||||||
|
|
||||||
@ -3142,7 +3201,7 @@ dict_stats_update(
|
|||||||
return(err);
|
return(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dict_stats_save(table, trx);
|
err = dict_stats_save(table, NULL);
|
||||||
|
|
||||||
return(err);
|
return(err);
|
||||||
}
|
}
|
||||||
@ -3178,7 +3237,7 @@ dict_stats_update(
|
|||||||
|
|
||||||
if (dict_stats_persistent_storage_check(false)) {
|
if (dict_stats_persistent_storage_check(false)) {
|
||||||
|
|
||||||
return(dict_stats_save(table, trx));
|
return(dict_stats_save(table, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
return(DB_STATS_DO_NOT_EXIST);
|
return(DB_STATS_DO_NOT_EXIST);
|
||||||
@ -3257,9 +3316,9 @@ dict_stats_update(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dict_stats_auto_recalc_is_enabled(table)) {
|
if (dict_stats_auto_recalc_is_enabled(table)) {
|
||||||
return dict_stats_update(
|
return(dict_stats_update(
|
||||||
table, DICT_STATS_RECALC_PERSISTENT,
|
table,
|
||||||
trx);
|
DICT_STATS_RECALC_PERSISTENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
ib::info() << "Trying to use table " << table->name
|
ib::info() << "Trying to use table " << table->name
|
||||||
@ -3307,20 +3366,25 @@ transient:
|
|||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Remove the persistent statistics for an index.
|
/*********************************************************************//**
|
||||||
@param[in] db_and_table schema and table name, e.g., 'db/table'
|
Removes the information for a particular index's stats from the persistent
|
||||||
@param[in] iname index name
|
storage if it exists and if there is data stored for this index.
|
||||||
@param[out] errstr error message (when not returning DB_SUCCESS)
|
This function creates its own trx and commits it.
|
||||||
@param[in] errstr_sz sizeof errstr
|
A note from Marko why we cannot edit user and sys_* tables in one trx:
|
||||||
@param[in,out] trx transaction
|
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.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_drop_index(
|
dict_stats_drop_index(
|
||||||
const char* db_and_table,
|
/*==================*/
|
||||||
const char* iname,
|
const char* db_and_table,/*!< in: db and table, e.g. 'db/table' */
|
||||||
char* errstr,
|
const char* iname, /*!< in: index name */
|
||||||
size_t errstr_sz,
|
char* errstr, /*!< out: error message if != DB_SUCCESS
|
||||||
trx_t* trx)
|
is returned */
|
||||||
|
ulint errstr_sz)/*!< in: size of the errstr buffer */
|
||||||
{
|
{
|
||||||
char db_utf8[MAX_DB_UTF8_LEN];
|
char db_utf8[MAX_DB_UTF8_LEN];
|
||||||
char table_utf8[MAX_TABLE_UTF8_LEN];
|
char table_utf8[MAX_TABLE_UTF8_LEN];
|
||||||
@ -3336,11 +3400,6 @@ dict_stats_drop_index(
|
|||||||
return(DB_SUCCESS);
|
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),
|
dict_fs2utf8(db_and_table, db_utf8, sizeof(db_utf8),
|
||||||
table_utf8, sizeof(table_utf8));
|
table_utf8, sizeof(table_utf8));
|
||||||
|
|
||||||
@ -3352,6 +3411,7 @@ dict_stats_drop_index(
|
|||||||
|
|
||||||
pars_info_add_str_literal(pinfo, "index_name", iname);
|
pars_info_add_str_literal(pinfo, "index_name", iname);
|
||||||
|
|
||||||
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
mutex_enter(&dict_sys->mutex);
|
mutex_enter(&dict_sys->mutex);
|
||||||
|
|
||||||
ret = dict_stats_exec_sql(
|
ret = dict_stats_exec_sql(
|
||||||
@ -3362,18 +3422,16 @@ dict_stats_drop_index(
|
|||||||
"database_name = :database_name AND\n"
|
"database_name = :database_name AND\n"
|
||||||
"table_name = :table_name AND\n"
|
"table_name = :table_name AND\n"
|
||||||
"index_name = :index_name;\n"
|
"index_name = :index_name;\n"
|
||||||
"END;\n", trx);
|
"END;\n", NULL);
|
||||||
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
mutex_exit(&dict_sys->mutex);
|
||||||
|
rw_lock_x_unlock(dict_operation_lock);
|
||||||
|
|
||||||
switch (ret) {
|
if (ret == DB_STATS_DO_NOT_EXIST) {
|
||||||
case DB_STATS_DO_NOT_EXIST:
|
ret = DB_SUCCESS;
|
||||||
case DB_SUCCESS:
|
}
|
||||||
return(DB_SUCCESS);
|
|
||||||
case DB_QUE_THR_SUSPENDED:
|
if (ret != DB_SUCCESS) {
|
||||||
ret = DB_LOCK_WAIT;
|
|
||||||
/* fall through */
|
|
||||||
default:
|
|
||||||
snprintf(errstr, errstr_sz,
|
snprintf(errstr, errstr_sz,
|
||||||
"Unable to delete statistics for index %s"
|
"Unable to delete statistics for index %s"
|
||||||
" from %s%s: %s. They can be deleted later using"
|
" from %s%s: %s. They can be deleted later using"
|
||||||
@ -3399,71 +3457,98 @@ dict_stats_drop_index(
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Delete table statistics.
|
/*********************************************************************//**
|
||||||
@param[in] db schema name
|
Executes
|
||||||
@param[in] t table name
|
DELETE FROM mysql.innodb_table_stats
|
||||||
@param[in,out] trx transaction
|
WHERE database_name = '...' AND table_name = '...';
|
||||||
|
Creates its own transaction and commits it.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_delete_from_table_stats(const char* db, const char* t, trx_t* trx)
|
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' */
|
||||||
{
|
{
|
||||||
pars_info_t* pinfo = pars_info_create();
|
pars_info_t* pinfo;
|
||||||
|
dberr_t ret;
|
||||||
|
|
||||||
pars_info_add_str_literal(pinfo, "database_name", db);
|
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
|
||||||
pars_info_add_str_literal(pinfo, "table_name", t);
|
ut_ad(mutex_own(&dict_sys->mutex));
|
||||||
|
|
||||||
return dict_stats_exec_sql(
|
pinfo = pars_info_create();
|
||||||
|
|
||||||
|
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(
|
||||||
pinfo,
|
pinfo,
|
||||||
"PROCEDURE DELETE_FROM_TABLE_STATS () IS\n"
|
"PROCEDURE DELETE_FROM_TABLE_STATS () IS\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"DELETE FROM \"" TABLE_STATS_NAME "\" WHERE\n"
|
"DELETE FROM \"" TABLE_STATS_NAME "\" WHERE\n"
|
||||||
"database_name = :database_name AND\n"
|
"database_name = :database_name AND\n"
|
||||||
"table_name = :table_name;\n"
|
"table_name = :table_name;\n"
|
||||||
"END;\n", trx);
|
"END;\n", NULL);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Delete index statistics.
|
/*********************************************************************//**
|
||||||
@param[in] db schema name
|
Executes
|
||||||
@param[in] t table name
|
DELETE FROM mysql.innodb_index_stats
|
||||||
@param[in,out] trx transaction
|
WHERE database_name = '...' AND table_name = '...';
|
||||||
|
Creates its own transaction and commits it.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_delete_from_index_stats(const char* db, const char* t, trx_t* trx)
|
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' */
|
||||||
{
|
{
|
||||||
pars_info_t* pinfo = pars_info_create();
|
pars_info_t* pinfo;
|
||||||
|
dberr_t ret;
|
||||||
|
|
||||||
pars_info_add_str_literal(pinfo, "database_name", db);
|
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
|
||||||
pars_info_add_str_literal(pinfo, "table_name", t);
|
ut_ad(mutex_own(&dict_sys->mutex));
|
||||||
|
|
||||||
return dict_stats_exec_sql(
|
pinfo = pars_info_create();
|
||||||
|
|
||||||
|
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(
|
||||||
pinfo,
|
pinfo,
|
||||||
"PROCEDURE DELETE_FROM_INDEX_STATS () IS\n"
|
"PROCEDURE DELETE_FROM_INDEX_STATS () IS\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
"DELETE FROM \"" INDEX_STATS_NAME "\" WHERE\n"
|
"DELETE FROM \"" INDEX_STATS_NAME "\" WHERE\n"
|
||||||
"database_name = :database_name AND\n"
|
"database_name = :database_name AND\n"
|
||||||
"table_name = :table_name;\n"
|
"table_name = :table_name;\n"
|
||||||
"END;\n", trx);
|
"END;\n", NULL);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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'
|
Removes the statistics for a table and all of its indexes from the
|
||||||
@param[out] errstr error message (when not returning DB_SUCCESS)
|
persistent statistics storage if it exists and if there is data stored for
|
||||||
@param[in] errstr_sz sizeof errstr
|
the table. This function creates its own transaction and commits it.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_drop_table(
|
dict_stats_drop_table(
|
||||||
const char* db_and_table,
|
/*==================*/
|
||||||
char* errstr,
|
const char* db_and_table, /*!< in: db and table, e.g. 'db/table' */
|
||||||
size_t errstr_sz,
|
char* errstr, /*!< out: error message
|
||||||
trx_t* trx)
|
if != DB_SUCCESS is returned */
|
||||||
|
ulint errstr_sz) /*!< in: size of errstr buffer */
|
||||||
{
|
{
|
||||||
char db_utf8[MAX_DB_UTF8_LEN];
|
char db_utf8[MAX_DB_UTF8_LEN];
|
||||||
char table_utf8[MAX_TABLE_UTF8_LEN];
|
char table_utf8[MAX_TABLE_UTF8_LEN];
|
||||||
dberr_t ret;
|
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
|
/* skip tables that do not contain a database name
|
||||||
e.g. if we are dropping SYS_TABLES */
|
e.g. if we are dropping SYS_TABLES */
|
||||||
if (strchr(db_and_table, '/') == NULL) {
|
if (strchr(db_and_table, '/') == NULL) {
|
||||||
@ -3478,32 +3563,24 @@ dict_stats_drop_table(
|
|||||||
return(DB_SUCCESS);
|
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),
|
dict_fs2utf8(db_and_table, db_utf8, sizeof(db_utf8),
|
||||||
table_utf8, sizeof(table_utf8));
|
table_utf8, sizeof(table_utf8));
|
||||||
|
|
||||||
ret = dict_stats_delete_from_table_stats(db_utf8, table_utf8, trx);
|
ret = dict_stats_delete_from_table_stats(db_utf8, table_utf8);
|
||||||
|
|
||||||
if (ret == DB_SUCCESS) {
|
if (ret == DB_SUCCESS) {
|
||||||
ret = dict_stats_delete_from_index_stats(
|
ret = dict_stats_delete_from_index_stats(db_utf8, table_utf8);
|
||||||
db_utf8, table_utf8, trx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ret) {
|
if (ret == DB_STATS_DO_NOT_EXIST) {
|
||||||
case DB_SUCCESS:
|
ret = DB_SUCCESS;
|
||||||
case DB_STATS_DO_NOT_EXIST:
|
}
|
||||||
return(DB_SUCCESS);
|
|
||||||
case DB_QUE_THR_SUSPENDED:
|
if (ret != DB_SUCCESS) {
|
||||||
ret = DB_LOCK_WAIT;
|
|
||||||
/* fall through */
|
|
||||||
default:
|
|
||||||
snprintf(errstr, errstr_sz,
|
snprintf(errstr, errstr_sz,
|
||||||
"Unable to delete statistics for table %s.%s: %s. "
|
"Unable to delete statistics for table %s.%s: %s."
|
||||||
"They can be deleted later using "
|
" They can be deleted later using"
|
||||||
|
|
||||||
" DELETE FROM %s WHERE"
|
" DELETE FROM %s WHERE"
|
||||||
" database_name = '%s' AND"
|
" database_name = '%s' AND"
|
||||||
@ -3526,30 +3603,36 @@ dict_stats_drop_table(
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rename table statistics.
|
/*********************************************************************//**
|
||||||
@param[in] old_dbname_utf8 old schema name
|
Executes
|
||||||
@param[in] old_tablename_utf8 old table name
|
UPDATE mysql.innodb_table_stats SET
|
||||||
@param[in] new_dbname_utf8 new schema name
|
database_name = '...', table_name = '...'
|
||||||
@param[in] new_tablename_utf8 new schema name
|
WHERE database_name = '...' AND table_name = '...';
|
||||||
@param[in,out] trx transaction
|
Creates its own transaction and commits it.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_rename_in_table_stats(
|
dict_stats_rename_table_in_table_stats(
|
||||||
const char* old_dbname_utf8,
|
/*===================================*/
|
||||||
const char* old_tablename_utf8,
|
const char* old_dbname_utf8,/*!< in: database name, e.g. 'olddb' */
|
||||||
const char* new_dbname_utf8,
|
const char* old_tablename_utf8,/*!< in: table name, e.g. 'oldtable' */
|
||||||
const char* new_tablename_utf8,
|
const char* new_dbname_utf8,/*!< in: database name, e.g. 'newdb' */
|
||||||
trx_t* trx)
|
const char* new_tablename_utf8)/*!< in: table name, e.g. 'newtable' */
|
||||||
{
|
{
|
||||||
pars_info_t* pinfo = pars_info_create();
|
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_add_str_literal(pinfo, "old_dbname_utf8", old_dbname_utf8);
|
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, "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_dbname_utf8", new_dbname_utf8);
|
||||||
pars_info_add_str_literal(pinfo, "new_tablename_utf8", new_tablename_utf8);
|
pars_info_add_str_literal(pinfo, "new_tablename_utf8", new_tablename_utf8);
|
||||||
|
|
||||||
return dict_stats_exec_sql(
|
ret = dict_stats_exec_sql(
|
||||||
pinfo,
|
pinfo,
|
||||||
"PROCEDURE RENAME_TABLE_IN_TABLE_STATS () IS\n"
|
"PROCEDURE RENAME_TABLE_IN_TABLE_STATS () IS\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
@ -3559,33 +3642,41 @@ dict_stats_rename_in_table_stats(
|
|||||||
"WHERE\n"
|
"WHERE\n"
|
||||||
"database_name = :old_dbname_utf8 AND\n"
|
"database_name = :old_dbname_utf8 AND\n"
|
||||||
"table_name = :old_tablename_utf8;\n"
|
"table_name = :old_tablename_utf8;\n"
|
||||||
"END;\n", trx);
|
"END;\n", NULL);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rename index statistics.
|
/*********************************************************************//**
|
||||||
@param[in] old_dbname_utf8 old schema name
|
Executes
|
||||||
@param[in] old_tablename_utf8 old table name
|
UPDATE mysql.innodb_index_stats SET
|
||||||
@param[in] new_dbname_utf8 new schema name
|
database_name = '...', table_name = '...'
|
||||||
@param[in] new_tablename_utf8 new schema name
|
WHERE database_name = '...' AND table_name = '...';
|
||||||
@param[in,out] trx transaction
|
Creates its own transaction and commits it.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_rename_in_index_stats(
|
dict_stats_rename_table_in_index_stats(
|
||||||
const char* old_dbname_utf8,
|
/*===================================*/
|
||||||
const char* old_tablename_utf8,
|
const char* old_dbname_utf8,/*!< in: database name, e.g. 'olddb' */
|
||||||
const char* new_dbname_utf8,
|
const char* old_tablename_utf8,/*!< in: table name, e.g. 'oldtable' */
|
||||||
const char* new_tablename_utf8,
|
const char* new_dbname_utf8,/*!< in: database name, e.g. 'newdb' */
|
||||||
trx_t* trx)
|
const char* new_tablename_utf8)/*!< in: table name, e.g. 'newtable' */
|
||||||
{
|
{
|
||||||
pars_info_t* pinfo = pars_info_create();
|
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_add_str_literal(pinfo, "old_dbname_utf8", old_dbname_utf8);
|
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, "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_dbname_utf8", new_dbname_utf8);
|
||||||
pars_info_add_str_literal(pinfo, "new_tablename_utf8", new_tablename_utf8);
|
pars_info_add_str_literal(pinfo, "new_tablename_utf8", new_tablename_utf8);
|
||||||
|
|
||||||
return dict_stats_exec_sql(
|
ret = dict_stats_exec_sql(
|
||||||
pinfo,
|
pinfo,
|
||||||
"PROCEDURE RENAME_TABLE_IN_INDEX_STATS () IS\n"
|
"PROCEDURE RENAME_TABLE_IN_INDEX_STATS () IS\n"
|
||||||
"BEGIN\n"
|
"BEGIN\n"
|
||||||
@ -3595,23 +3686,23 @@ dict_stats_rename_in_index_stats(
|
|||||||
"WHERE\n"
|
"WHERE\n"
|
||||||
"database_name = :old_dbname_utf8 AND\n"
|
"database_name = :old_dbname_utf8 AND\n"
|
||||||
"table_name = :old_tablename_utf8;\n"
|
"table_name = :old_tablename_utf8;\n"
|
||||||
"END;\n", trx);
|
"END;\n", NULL);
|
||||||
|
|
||||||
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Rename a table in the InnoDB persistent statistics storage.
|
/*********************************************************************//**
|
||||||
@param[in] old_name old schema and table name, e.g., 'db/table'
|
Renames a table in InnoDB persistent stats storage.
|
||||||
@param[in] new_name new schema and table name, e.g., 'db/table'
|
This function creates its own transaction and commits it.
|
||||||
@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 */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_rename_table(
|
dict_stats_rename_table(
|
||||||
const char* old_name,
|
/*====================*/
|
||||||
const char* new_name,
|
const char* old_name, /*!< in: old name, e.g. 'db/table' */
|
||||||
char* errstr,
|
const char* new_name, /*!< in: new name, e.g. 'db/table' */
|
||||||
size_t errstr_sz,
|
char* errstr, /*!< out: error string if != DB_SUCCESS
|
||||||
trx_t* trx)
|
is returned */
|
||||||
|
size_t errstr_sz) /*!< in: errstr size */
|
||||||
{
|
{
|
||||||
char old_db_utf8[MAX_DB_UTF8_LEN];
|
char old_db_utf8[MAX_DB_UTF8_LEN];
|
||||||
char new_db_utf8[MAX_DB_UTF8_LEN];
|
char new_db_utf8[MAX_DB_UTF8_LEN];
|
||||||
@ -3619,6 +3710,9 @@ dict_stats_rename_table(
|
|||||||
char new_table_utf8[MAX_TABLE_UTF8_LEN];
|
char new_table_utf8[MAX_TABLE_UTF8_LEN];
|
||||||
dberr_t ret;
|
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 */
|
/* skip innodb_table_stats and innodb_index_stats themselves */
|
||||||
if (strcmp(old_name, TABLE_STATS_NAME) == 0
|
if (strcmp(old_name, TABLE_STATS_NAME) == 0
|
||||||
|| strcmp(old_name, INDEX_STATS_NAME) == 0
|
|| strcmp(old_name, INDEX_STATS_NAME) == 0
|
||||||
@ -3628,95 +3722,45 @@ dict_stats_rename_table(
|
|||||||
return(DB_SUCCESS);
|
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),
|
dict_fs2utf8(old_name, old_db_utf8, sizeof(old_db_utf8),
|
||||||
old_table_utf8, sizeof(old_table_utf8));
|
old_table_utf8, sizeof(old_table_utf8));
|
||||||
|
|
||||||
dict_fs2utf8(new_name, new_db_utf8, sizeof(new_db_utf8),
|
dict_fs2utf8(new_name, new_db_utf8, sizeof(new_db_utf8),
|
||||||
new_table_utf8, sizeof(new_table_utf8));
|
new_table_utf8, sizeof(new_table_utf8));
|
||||||
|
|
||||||
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
|
mutex_enter(&dict_sys->mutex);
|
||||||
|
|
||||||
ulint n_attempts = 0;
|
ulint n_attempts = 0;
|
||||||
do {
|
do {
|
||||||
trx_savept_t savept = trx_savept_take(trx);
|
n_attempts++;
|
||||||
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
ret = dict_stats_rename_table_in_table_stats(
|
||||||
|
|
||||||
ret = dict_stats_rename_in_table_stats(
|
|
||||||
old_db_utf8, old_table_utf8,
|
old_db_utf8, old_table_utf8,
|
||||||
new_db_utf8, new_table_utf8, trx);
|
new_db_utf8, new_table_utf8);
|
||||||
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
if (ret == DB_DUPLICATE_KEY) {
|
||||||
|
|
||||||
switch (ret) {
|
|
||||||
case DB_DUPLICATE_KEY:
|
|
||||||
trx_rollback_to_savepoint(trx, &savept);
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
|
||||||
dict_stats_delete_from_table_stats(
|
dict_stats_delete_from_table_stats(
|
||||||
new_db_utf8, new_table_utf8, trx);
|
new_db_utf8, new_table_utf8);
|
||||||
mutex_exit(&dict_sys->mutex);
|
|
||||||
/* fall through */
|
|
||||||
case DB_LOCK_WAIT_TIMEOUT:
|
|
||||||
trx->error_state = DB_SUCCESS;
|
|
||||||
os_thread_sleep(200000 /* 0.2 sec */);
|
|
||||||
continue;
|
|
||||||
case DB_STATS_DO_NOT_EXIST:
|
|
||||||
ret = DB_SUCCESS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
if (ret == DB_STATS_DO_NOT_EXIST) {
|
||||||
} while (++n_attempts < 5);
|
ret = DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
const char* table_name = TABLE_STATS_NAME_PRINT;
|
if (ret != DB_SUCCESS) {
|
||||||
|
mutex_exit(&dict_sys->mutex);
|
||||||
if (ret != DB_SUCCESS) {
|
rw_lock_x_unlock(dict_operation_lock);
|
||||||
goto err_exit;
|
os_thread_sleep(200000 /* 0.2 sec */);
|
||||||
}
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
|
|
||||||
table_name = INDEX_STATS_NAME_PRINT;
|
|
||||||
|
|
||||||
n_attempts = 0;
|
|
||||||
do {
|
|
||||||
trx_savept_t savept = trx_savept_take(trx);
|
|
||||||
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
|
||||||
|
|
||||||
ret = dict_stats_rename_in_index_stats(
|
|
||||||
old_db_utf8, old_table_utf8,
|
|
||||||
new_db_utf8, new_table_utf8, trx);
|
|
||||||
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
|
||||||
|
|
||||||
switch (ret) {
|
|
||||||
case DB_DUPLICATE_KEY:
|
|
||||||
trx_rollback_to_savepoint(trx, &savept);
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
mutex_enter(&dict_sys->mutex);
|
||||||
dict_stats_delete_from_index_stats(
|
|
||||||
new_db_utf8, new_table_utf8, trx);
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
|
||||||
/* fall through */
|
|
||||||
case DB_LOCK_WAIT_TIMEOUT:
|
|
||||||
trx->error_state = DB_SUCCESS;
|
|
||||||
os_thread_sleep(200000 /* 0.2 sec */);
|
|
||||||
continue;
|
|
||||||
case DB_STATS_DO_NOT_EXIST:
|
|
||||||
ret = DB_SUCCESS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} while ((ret == DB_DEADLOCK
|
||||||
break;
|
|| ret == DB_DUPLICATE_KEY
|
||||||
} while (++n_attempts < 5);
|
|| ret == DB_LOCK_WAIT_TIMEOUT)
|
||||||
|
&& n_attempts < 5);
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
if (ret != DB_SUCCESS) {
|
||||||
err_exit:
|
|
||||||
snprintf(errstr, errstr_sz,
|
snprintf(errstr, errstr_sz,
|
||||||
"Unable to rename statistics from"
|
"Unable to rename statistics from"
|
||||||
" %s.%s to %s.%s in %s: %s."
|
" %s.%s to %s.%s in %s: %s."
|
||||||
@ -3731,10 +3775,69 @@ err_exit:
|
|||||||
|
|
||||||
old_db_utf8, old_table_utf8,
|
old_db_utf8, old_table_utf8,
|
||||||
new_db_utf8, new_table_utf8,
|
new_db_utf8, new_table_utf8,
|
||||||
table_name,
|
TABLE_STATS_NAME_PRINT,
|
||||||
ut_strerr(ret),
|
ut_strerr(ret),
|
||||||
|
|
||||||
table_name,
|
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);
|
||||||
|
}
|
||||||
|
/* else */
|
||||||
|
|
||||||
|
n_attempts = 0;
|
||||||
|
do {
|
||||||
|
n_attempts++;
|
||||||
|
|
||||||
|
ret = dict_stats_rename_table_in_index_stats(
|
||||||
|
old_db_utf8, old_table_utf8,
|
||||||
|
new_db_utf8, new_table_utf8);
|
||||||
|
|
||||||
|
if (ret == DB_DUPLICATE_KEY) {
|
||||||
|
dict_stats_delete_from_index_stats(
|
||||||
|
new_db_utf8, new_table_utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == DB_STATS_DO_NOT_EXIST) {
|
||||||
|
ret = DB_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != DB_SUCCESS) {
|
||||||
|
mutex_exit(&dict_sys->mutex);
|
||||||
|
rw_lock_x_unlock(dict_operation_lock);
|
||||||
|
os_thread_sleep(200000 /* 0.2 sec */);
|
||||||
|
rw_lock_x_lock(dict_operation_lock);
|
||||||
|
mutex_enter(&dict_sys->mutex);
|
||||||
|
}
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
if (ret != DB_SUCCESS) {
|
||||||
|
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,
|
new_db_utf8, new_table_utf8,
|
||||||
old_db_utf8, old_table_utf8);
|
old_db_utf8, old_table_utf8);
|
||||||
}
|
}
|
||||||
@ -3742,6 +3845,7 @@ err_exit:
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MYSQL_RENAME_INDEX
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
Renames an index in InnoDB persistent stats storage.
|
Renames an index in InnoDB persistent stats storage.
|
||||||
This function creates its own transaction and commits it.
|
This function creates its own transaction and commits it.
|
||||||
@ -3798,6 +3902,7 @@ dict_stats_rename_index(
|
|||||||
|
|
||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
#endif /* MYSQL_RENAME_INDEX */
|
||||||
|
|
||||||
/* tests @{ */
|
/* tests @{ */
|
||||||
#ifdef UNIV_ENABLE_UNIT_TEST_DICT_STATS
|
#ifdef UNIV_ENABLE_UNIT_TEST_DICT_STATS
|
||||||
|
@ -32,7 +32,6 @@ Created Apr 25, 2012 Vasil Dimov
|
|||||||
#include "srv0start.h"
|
#include "srv0start.h"
|
||||||
#include "ut0new.h"
|
#include "ut0new.h"
|
||||||
#include "fil0fil.h"
|
#include "fil0fil.h"
|
||||||
#include "trx0trx.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -181,7 +180,7 @@ dict_stats_update_if_needed(dict_table_t* table)
|
|||||||
|
|
||||||
if (counter > threshold) {
|
if (counter > threshold) {
|
||||||
/* this will reset table->stat_modified_counter to 0 */
|
/* this will reset table->stat_modified_counter to 0 */
|
||||||
dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT, NULL);
|
dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +323,8 @@ Get the first table that has been added for auto recalc and eventually
|
|||||||
update its stats. */
|
update its stats. */
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
dict_stats_process_entry_from_recalc_pool(trx_t* trx)
|
dict_stats_process_entry_from_recalc_pool()
|
||||||
|
/*=======================================*/
|
||||||
{
|
{
|
||||||
table_id_t table_id;
|
table_id_t table_id;
|
||||||
|
|
||||||
@ -378,12 +378,8 @@ dict_stats_process_entry_from_recalc_pool(trx_t* trx)
|
|||||||
dict_stats_recalc_pool_add(table);
|
dict_stats_recalc_pool_add(table);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
trx->error_state = DB_SUCCESS;
|
|
||||||
++trx->will_lock;
|
dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT);
|
||||||
dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT, trx);
|
|
||||||
if (trx->state != TRX_STATE_NOT_STARTED) {
|
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_enter(&dict_sys->mutex);
|
mutex_enter(&dict_sys->mutex);
|
||||||
@ -444,9 +440,6 @@ DECLARE_THREAD(dict_stats_thread)(void*)
|
|||||||
*/
|
*/
|
||||||
#endif /* UNIV_PFS_THREAD */
|
#endif /* UNIV_PFS_THREAD */
|
||||||
|
|
||||||
trx_t* trx = trx_allocate_for_background();
|
|
||||||
ut_d(trx->persistent_stats = true);
|
|
||||||
|
|
||||||
while (!dict_stats_start_shutdown) {
|
while (!dict_stats_start_shutdown) {
|
||||||
|
|
||||||
/* Wake up periodically even if not signaled. This is
|
/* Wake up periodically even if not signaled. This is
|
||||||
@ -472,14 +465,12 @@ DECLARE_THREAD(dict_stats_thread)(void*)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_stats_process_entry_from_recalc_pool(trx);
|
dict_stats_process_entry_from_recalc_pool();
|
||||||
dict_defrag_process_entries_from_defrag_pool(trx);
|
dict_defrag_process_entries_from_defrag_pool();
|
||||||
|
|
||||||
os_event_reset(dict_stats_event);
|
os_event_reset(dict_stats_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_d(trx->persistent_stats = false);
|
|
||||||
trx_free_for_background(trx);
|
|
||||||
srv_dict_stats_thread_active = false;
|
srv_dict_stats_thread_active = false;
|
||||||
|
|
||||||
os_event_set(dict_stats_shutdown_event);
|
os_event_set(dict_stats_shutdown_event);
|
||||||
|
@ -6470,22 +6470,7 @@ no_such_table:
|
|||||||
|
|
||||||
/* No point to init any statistics if tablespace is still encrypted. */
|
/* No point to init any statistics if tablespace is still encrypted. */
|
||||||
if (ib_table->is_readable()) {
|
if (ib_table->is_readable()) {
|
||||||
trx_t* trx = check_trx_exists(thd);
|
dict_stats_init(ib_table);
|
||||||
bool alloc = !trx_state_eq(trx, TRX_STATE_NOT_STARTED);
|
|
||||||
|
|
||||||
if (alloc) {
|
|
||||||
trx = trx_allocate_for_background();
|
|
||||||
}
|
|
||||||
ut_ad(!trx->persistent_stats);
|
|
||||||
ut_d(trx->persistent_stats = true);
|
|
||||||
trx->error_state = DB_SUCCESS;
|
|
||||||
++trx->will_lock;
|
|
||||||
dict_stats_init(ib_table, trx);
|
|
||||||
innobase_commit_low(trx);
|
|
||||||
ut_d(trx->persistent_stats = false);
|
|
||||||
if (alloc) {
|
|
||||||
trx_free_for_background(trx);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ib_table->stat_initialized = 1;
|
ib_table->stat_initialized = 1;
|
||||||
}
|
}
|
||||||
@ -13274,10 +13259,7 @@ create_table_info_t::create_table_update_dict()
|
|||||||
|
|
||||||
innobase_copy_frm_flags_from_create_info(innobase_table, m_create_info);
|
innobase_copy_frm_flags_from_create_info(innobase_table, m_create_info);
|
||||||
|
|
||||||
++m_trx->will_lock;
|
dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE);
|
||||||
m_trx->error_state = DB_SUCCESS;
|
|
||||||
dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE, m_trx);
|
|
||||||
innobase_commit_low(m_trx);
|
|
||||||
|
|
||||||
if (innobase_table) {
|
if (innobase_table) {
|
||||||
/* We update the highest file format in the system table
|
/* We update the highest file format in the system table
|
||||||
@ -13539,8 +13521,7 @@ ha_innobase::discard_or_import_tablespace(
|
|||||||
|
|
||||||
/* Adjust the persistent statistics. */
|
/* Adjust the persistent statistics. */
|
||||||
ret = dict_stats_update(dict_table,
|
ret = dict_stats_update(dict_table,
|
||||||
DICT_STATS_RECALC_PERSISTENT,
|
DICT_STATS_RECALC_PERSISTENT);
|
||||||
m_prebuilt->trx);
|
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
if (ret != DB_SUCCESS) {
|
||||||
push_warning_printf(
|
push_warning_printf(
|
||||||
@ -13548,11 +13529,8 @@ ha_innobase::discard_or_import_tablespace(
|
|||||||
Sql_condition::WARN_LEVEL_WARN,
|
Sql_condition::WARN_LEVEL_WARN,
|
||||||
ER_ALTER_INFO,
|
ER_ALTER_INFO,
|
||||||
"Error updating stats for table '%s'"
|
"Error updating stats for table '%s'"
|
||||||
" after table import: %s",
|
" after table rebuild: %s",
|
||||||
dict_table->name.m_name, ut_strerr(ret));
|
dict_table->name.m_name, ut_strerr(ret));
|
||||||
trx_rollback_to_savepoint(m_prebuilt->trx, NULL);
|
|
||||||
} else {
|
|
||||||
trx_commit_for_mysql(m_prebuilt->trx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14031,6 +14009,8 @@ ha_innobase::rename_table(
|
|||||||
|
|
||||||
innobase_commit_low(trx);
|
innobase_commit_low(trx);
|
||||||
|
|
||||||
|
trx_free_for_mysql(trx);
|
||||||
|
|
||||||
if (error == DB_SUCCESS) {
|
if (error == DB_SUCCESS) {
|
||||||
char norm_from[MAX_FULL_NAME_LEN];
|
char norm_from[MAX_FULL_NAME_LEN];
|
||||||
char norm_to[MAX_FULL_NAME_LEN];
|
char norm_to[MAX_FULL_NAME_LEN];
|
||||||
@ -14040,24 +14020,17 @@ ha_innobase::rename_table(
|
|||||||
normalize_table_name(norm_from, from);
|
normalize_table_name(norm_from, from);
|
||||||
normalize_table_name(norm_to, to);
|
normalize_table_name(norm_to, to);
|
||||||
|
|
||||||
trx->error_state = DB_SUCCESS;
|
|
||||||
++trx->will_lock;
|
|
||||||
ret = dict_stats_rename_table(norm_from, norm_to,
|
ret = dict_stats_rename_table(norm_from, norm_to,
|
||||||
errstr, sizeof errstr, trx);
|
errstr, sizeof(errstr));
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
if (ret != DB_SUCCESS) {
|
||||||
trx_rollback_to_savepoint(trx, NULL);
|
|
||||||
ib::error() << errstr;
|
ib::error() << errstr;
|
||||||
|
|
||||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||||
ER_LOCK_WAIT_TIMEOUT, errstr);
|
ER_LOCK_WAIT_TIMEOUT, errstr);
|
||||||
} else {
|
|
||||||
innobase_commit_low(trx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trx_free_for_mysql(trx);
|
|
||||||
|
|
||||||
/* Add a special case to handle the Duplicated Key error
|
/* Add a special case to handle the Duplicated Key error
|
||||||
and return DB_ERROR instead.
|
and return DB_ERROR instead.
|
||||||
This is to avoid a possible SIGSEGV error from mysql error
|
This is to avoid a possible SIGSEGV error from mysql error
|
||||||
@ -14595,34 +14568,18 @@ ha_innobase::info_low(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(!mutex_own(&dict_sys->mutex));
|
ut_ad(!mutex_own(&dict_sys->mutex));
|
||||||
/* Do not use prebuilt->trx in case this is
|
ret = dict_stats_update(ib_table, opt);
|
||||||
called in the middle of a transaction. We
|
|
||||||
should commit the transaction after
|
|
||||||
dict_stats_update() in order not to hog locks
|
|
||||||
on the mysql.innodb_table_stats,
|
|
||||||
mysql.innodb_index_stats tables. */
|
|
||||||
trx_t* trx = trx_allocate_for_background();
|
|
||||||
ut_d(trx->persistent_stats = true);
|
|
||||||
++trx->will_lock;
|
|
||||||
ret = dict_stats_update(ib_table, opt, trx);
|
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
if (ret != DB_SUCCESS) {
|
||||||
m_prebuilt->trx->op_info = "";
|
m_prebuilt->trx->op_info = "";
|
||||||
trx_rollback_to_savepoint(trx, NULL);
|
|
||||||
} else {
|
|
||||||
m_prebuilt->trx->op_info =
|
|
||||||
"returning various info to MySQL";
|
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_d(trx->persistent_stats = false);
|
|
||||||
trx_free_for_background(trx);
|
|
||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
|
||||||
DBUG_RETURN(HA_ERR_GENERIC);
|
DBUG_RETURN(HA_ERR_GENERIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_prebuilt->trx->op_info =
|
||||||
|
"returning various info to MariaDB";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stats.update_time = (ulong) ib_table->update_time;
|
stats.update_time = (ulong) ib_table->update_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8214,27 +8214,29 @@ commit_cache_norebuild(
|
|||||||
/** Adjust the persistent statistics after non-rebuilding ALTER TABLE.
|
/** Adjust the persistent statistics after non-rebuilding ALTER TABLE.
|
||||||
Remove statistics for dropped indexes, add statistics for created indexes
|
Remove statistics for dropped indexes, add statistics for created indexes
|
||||||
and rename statistics for renamed indexes.
|
and rename statistics for renamed indexes.
|
||||||
@param ha_alter_info Data used during in-place alter
|
@param ha_alter_info Data used during in-place alter
|
||||||
@param ctx In-place ALTER TABLE context
|
@param ctx In-place ALTER TABLE context
|
||||||
@param table_name Table name in MySQL
|
@param altered_table MySQL table that is being altered
|
||||||
@param trx transaction
|
@param table_name Table name in MySQL
|
||||||
@return error code */
|
@param thd MySQL connection
|
||||||
|
*/
|
||||||
static
|
static
|
||||||
dberr_t
|
void
|
||||||
alter_stats_norebuild(
|
alter_stats_norebuild(
|
||||||
|
/*==================*/
|
||||||
Alter_inplace_info* ha_alter_info,
|
Alter_inplace_info* ha_alter_info,
|
||||||
ha_innobase_inplace_ctx* ctx,
|
ha_innobase_inplace_ctx* ctx,
|
||||||
|
TABLE* altered_table,
|
||||||
const char* table_name,
|
const char* table_name,
|
||||||
trx_t* trx)
|
THD* thd)
|
||||||
{
|
{
|
||||||
dberr_t err = DB_SUCCESS;
|
|
||||||
ulint i;
|
ulint i;
|
||||||
|
|
||||||
DBUG_ENTER("alter_stats_norebuild");
|
DBUG_ENTER("alter_stats_norebuild");
|
||||||
DBUG_ASSERT(!ctx->need_rebuild());
|
DBUG_ASSERT(!ctx->need_rebuild());
|
||||||
|
|
||||||
if (!dict_stats_is_persistent_enabled(ctx->new_table)) {
|
if (!dict_stats_is_persistent_enabled(ctx->new_table)) {
|
||||||
DBUG_RETURN(err);
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete corresponding rows from the stats table. We do this
|
/* Delete corresponding rows from the stats table. We do this
|
||||||
@ -8263,13 +8265,10 @@ alter_stats_norebuild(
|
|||||||
|
|
||||||
char errstr[1024];
|
char errstr[1024];
|
||||||
|
|
||||||
dberr_t err2 = dict_stats_drop_index(
|
if (dict_stats_drop_index(
|
||||||
ctx->new_table->name.m_name, key->name,
|
ctx->new_table->name.m_name, key->name,
|
||||||
errstr, sizeof errstr, trx);
|
errstr, sizeof errstr) != DB_SUCCESS) {
|
||||||
|
push_warning(thd,
|
||||||
if (err2 != DB_SUCCESS) {
|
|
||||||
err = err2;
|
|
||||||
push_warning(trx->mysql_thd,
|
|
||||||
Sql_condition::WARN_LEVEL_WARN,
|
Sql_condition::WARN_LEVEL_WARN,
|
||||||
ER_LOCK_WAIT_TIMEOUT, errstr);
|
ER_LOCK_WAIT_TIMEOUT, errstr);
|
||||||
}
|
}
|
||||||
@ -8305,36 +8304,34 @@ alter_stats_norebuild(
|
|||||||
DBUG_ASSERT(index->table == ctx->new_table);
|
DBUG_ASSERT(index->table == ctx->new_table);
|
||||||
|
|
||||||
if (!(index->type & DICT_FTS)) {
|
if (!(index->type & DICT_FTS)) {
|
||||||
dict_stats_init(ctx->new_table, trx);
|
dict_stats_init(ctx->new_table);
|
||||||
dberr_t err2 = dict_stats_update_for_index(index, trx);
|
dict_stats_update_for_index(index);
|
||||||
if (err2 != DB_SUCCESS) {
|
|
||||||
err = err2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(err);
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Adjust the persistent statistics after rebuilding ALTER TABLE.
|
/** Adjust the persistent statistics after rebuilding ALTER TABLE.
|
||||||
Remove statistics for dropped indexes, add statistics for created indexes
|
Remove statistics for dropped indexes, add statistics for created indexes
|
||||||
and rename statistics for renamed indexes.
|
and rename statistics for renamed indexes.
|
||||||
@param table InnoDB table that was rebuilt by ALTER TABLE
|
@param table InnoDB table that was rebuilt by ALTER TABLE
|
||||||
@param table_name Table name in MySQL
|
@param table_name Table name in MySQL
|
||||||
@param trx transaction
|
@param thd MySQL connection
|
||||||
@return error code */
|
*/
|
||||||
static
|
static
|
||||||
dberr_t
|
void
|
||||||
alter_stats_rebuild(
|
alter_stats_rebuild(
|
||||||
|
/*================*/
|
||||||
dict_table_t* table,
|
dict_table_t* table,
|
||||||
const char* table_name,
|
const char* table_name,
|
||||||
trx_t* trx)
|
THD* thd)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("alter_stats_rebuild");
|
DBUG_ENTER("alter_stats_rebuild");
|
||||||
|
|
||||||
if (dict_table_is_discarded(table)
|
if (dict_table_is_discarded(table)
|
||||||
|| !dict_stats_is_persistent_enabled(table)) {
|
|| !dict_stats_is_persistent_enabled(table)) {
|
||||||
DBUG_RETURN(DB_SUCCESS);
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
@ -8347,24 +8344,7 @@ alter_stats_rebuild(
|
|||||||
table->file_unreadable = true;
|
table->file_unreadable = true;
|
||||||
);
|
);
|
||||||
|
|
||||||
char errstr[1024];
|
dberr_t ret = dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT);
|
||||||
mutex_enter(&dict_sys->mutex);
|
|
||||||
dberr_t ret = dict_stats_drop_table(table->name.m_name,
|
|
||||||
errstr, sizeof errstr, trx);
|
|
||||||
mutex_exit(&dict_sys->mutex);
|
|
||||||
if (ret != DB_SUCCESS) {
|
|
||||||
push_warning_printf(
|
|
||||||
trx->mysql_thd,
|
|
||||||
Sql_condition::WARN_LEVEL_WARN,
|
|
||||||
ER_ALTER_INFO,
|
|
||||||
"Deleting persistent statistics"
|
|
||||||
" for rebuilt table '%s' in"
|
|
||||||
" InnoDB failed: %s",
|
|
||||||
table_name, errstr);
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT, trx);
|
|
||||||
|
|
||||||
DBUG_EXECUTE_IF(
|
DBUG_EXECUTE_IF(
|
||||||
"ib_rename_index_fail2",
|
"ib_rename_index_fail2",
|
||||||
@ -8373,7 +8353,7 @@ alter_stats_rebuild(
|
|||||||
|
|
||||||
if (ret != DB_SUCCESS) {
|
if (ret != DB_SUCCESS) {
|
||||||
push_warning_printf(
|
push_warning_printf(
|
||||||
trx->mysql_thd,
|
thd,
|
||||||
Sql_condition::WARN_LEVEL_WARN,
|
Sql_condition::WARN_LEVEL_WARN,
|
||||||
ER_ALTER_INFO,
|
ER_ALTER_INFO,
|
||||||
"Error updating stats for table '%s'"
|
"Error updating stats for table '%s'"
|
||||||
@ -8381,7 +8361,7 @@ alter_stats_rebuild(
|
|||||||
table_name, ut_strerr(ret));
|
table_name, ut_strerr(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
@ -8688,36 +8668,6 @@ ha_innobase::commit_inplace_alter_table(
|
|||||||
if (fail) {
|
if (fail) {
|
||||||
trx_rollback_for_mysql(trx);
|
trx_rollback_for_mysql(trx);
|
||||||
} else if (!new_clustered) {
|
} else if (!new_clustered) {
|
||||||
if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol) {
|
|
||||||
DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1);
|
|
||||||
bool warned = false;
|
|
||||||
|
|
||||||
for (inplace_alter_handler_ctx** pctx = ctx_array;
|
|
||||||
*pctx; pctx++) {
|
|
||||||
ha_innobase_inplace_ctx* ctx
|
|
||||||
= static_cast<ha_innobase_inplace_ctx*>
|
|
||||||
(*pctx);
|
|
||||||
|
|
||||||
DBUG_ASSERT(!ctx->need_rebuild());
|
|
||||||
char errstr[1024];
|
|
||||||
if (dict_stats_drop_table(
|
|
||||||
ctx->old_table->name.m_name,
|
|
||||||
errstr, sizeof errstr, trx)
|
|
||||||
!= DB_SUCCESS && !warned) {
|
|
||||||
warned = true;
|
|
||||||
push_warning_printf(
|
|
||||||
m_user_thd,
|
|
||||||
Sql_condition::WARN_LEVEL_WARN,
|
|
||||||
ER_ALTER_INFO,
|
|
||||||
"Deleting persistent "
|
|
||||||
"statistics for table '%s' in"
|
|
||||||
" InnoDB failed: %s",
|
|
||||||
table_share->table_name.str,
|
|
||||||
errstr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
} else {
|
} else {
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
@ -8974,6 +8924,23 @@ foreign_fail:
|
|||||||
m_prebuilt->table = dict_table_open_on_name(
|
m_prebuilt->table = dict_table_open_on_name(
|
||||||
tb_name, TRUE, TRUE, DICT_ERR_IGNORE_NONE);
|
tb_name, TRUE, TRUE, DICT_ERR_IGNORE_NONE);
|
||||||
|
|
||||||
|
/* Drop outdated table stats. */
|
||||||
|
char errstr[1024];
|
||||||
|
if (dict_stats_drop_table(
|
||||||
|
m_prebuilt->table->name.m_name,
|
||||||
|
errstr, sizeof(errstr))
|
||||||
|
!= DB_SUCCESS) {
|
||||||
|
push_warning_printf(
|
||||||
|
m_user_thd,
|
||||||
|
Sql_condition::WARN_LEVEL_WARN,
|
||||||
|
ER_ALTER_INFO,
|
||||||
|
"Deleting persistent statistics"
|
||||||
|
" for table '%s' in"
|
||||||
|
" InnoDB failed: %s",
|
||||||
|
table->s->table_name.str,
|
||||||
|
errstr);
|
||||||
|
}
|
||||||
|
|
||||||
row_mysql_unlock_data_dictionary(trx);
|
row_mysql_unlock_data_dictionary(trx);
|
||||||
trx_free_for_mysql(trx);
|
trx_free_for_mysql(trx);
|
||||||
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
|
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
|
||||||
@ -9029,6 +8996,41 @@ foreign_fail:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (new_clustered) {
|
if (new_clustered) {
|
||||||
|
/* Since the table has been rebuilt, we remove
|
||||||
|
all persistent statistics corresponding to the
|
||||||
|
old copy of the table (which was renamed to
|
||||||
|
ctx->tmp_name). */
|
||||||
|
|
||||||
|
char errstr[1024];
|
||||||
|
|
||||||
|
DBUG_ASSERT(0 == strcmp(ctx->old_table->name.m_name,
|
||||||
|
ctx->tmp_name));
|
||||||
|
|
||||||
|
DBUG_EXECUTE_IF(
|
||||||
|
"ib_rename_index_fail3",
|
||||||
|
DBUG_SET("+d,innodb_report_deadlock");
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dict_stats_drop_table(
|
||||||
|
ctx->new_table->name.m_name,
|
||||||
|
errstr, sizeof(errstr))
|
||||||
|
!= DB_SUCCESS) {
|
||||||
|
push_warning_printf(
|
||||||
|
m_user_thd,
|
||||||
|
Sql_condition::WARN_LEVEL_WARN,
|
||||||
|
ER_ALTER_INFO,
|
||||||
|
"Deleting persistent statistics"
|
||||||
|
" for rebuilt table '%s' in"
|
||||||
|
" InnoDB failed: %s",
|
||||||
|
table->s->table_name.str,
|
||||||
|
errstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_EXECUTE_IF(
|
||||||
|
"ib_rename_index_fail3",
|
||||||
|
DBUG_SET("-d,innodb_report_deadlock");
|
||||||
|
);
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("ib_ddl_crash_before_commit",
|
DBUG_EXECUTE_IF("ib_ddl_crash_before_commit",
|
||||||
DBUG_SUICIDE(););
|
DBUG_SUICIDE(););
|
||||||
|
|
||||||
@ -9074,14 +9076,11 @@ foreign_fail:
|
|||||||
}
|
}
|
||||||
|
|
||||||
row_mysql_unlock_data_dictionary(trx);
|
row_mysql_unlock_data_dictionary(trx);
|
||||||
trx->error_state = DB_SUCCESS;
|
trx_free_for_mysql(trx);
|
||||||
++trx->will_lock;
|
|
||||||
|
|
||||||
/* TODO: The following code could be executed
|
/* TODO: The following code could be executed
|
||||||
while allowing concurrent access to the table
|
while allowing concurrent access to the table
|
||||||
(MDL downgrade). */
|
(MDL downgrade). */
|
||||||
trx->mysql_thd = m_user_thd;
|
|
||||||
dberr_t stats_err = DB_SUCCESS;
|
|
||||||
|
|
||||||
if (new_clustered) {
|
if (new_clustered) {
|
||||||
for (inplace_alter_handler_ctx** pctx = ctx_array;
|
for (inplace_alter_handler_ctx** pctx = ctx_array;
|
||||||
@ -9090,11 +9089,10 @@ foreign_fail:
|
|||||||
= static_cast<ha_innobase_inplace_ctx*>
|
= static_cast<ha_innobase_inplace_ctx*>
|
||||||
(*pctx);
|
(*pctx);
|
||||||
DBUG_ASSERT(ctx->need_rebuild());
|
DBUG_ASSERT(ctx->need_rebuild());
|
||||||
stats_err = alter_stats_rebuild(
|
|
||||||
ctx->new_table, table->s->table_name.str, trx);
|
alter_stats_rebuild(
|
||||||
if (stats_err != DB_SUCCESS) {
|
ctx->new_table, table->s->table_name.str,
|
||||||
break;
|
m_user_thd);
|
||||||
}
|
|
||||||
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
|
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
|
||||||
crash_inject_count++);
|
crash_inject_count++);
|
||||||
}
|
}
|
||||||
@ -9106,25 +9104,14 @@ foreign_fail:
|
|||||||
(*pctx);
|
(*pctx);
|
||||||
DBUG_ASSERT(!ctx->need_rebuild());
|
DBUG_ASSERT(!ctx->need_rebuild());
|
||||||
|
|
||||||
stats_err = alter_stats_norebuild(
|
alter_stats_norebuild(
|
||||||
ha_alter_info, ctx,
|
ha_alter_info, ctx, altered_table,
|
||||||
table->s->table_name.str, trx);
|
table->s->table_name.str, m_user_thd);
|
||||||
if (stats_err != DB_SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
|
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
|
||||||
crash_inject_count++);
|
crash_inject_count++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stats_err != DB_SUCCESS) {
|
|
||||||
trx_rollback_to_savepoint(trx, NULL);
|
|
||||||
} else {
|
|
||||||
trx_commit_for_mysql(trx);
|
|
||||||
}
|
|
||||||
|
|
||||||
trx_free_for_mysql(trx);
|
|
||||||
|
|
||||||
innobase_parse_hint_from_comment(
|
innobase_parse_hint_from_comment(
|
||||||
m_user_thd, m_prebuilt->table, altered_table->s);
|
m_user_thd, m_prebuilt->table, altered_table->s);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2016, 2017, MariaDB Corporation.
|
Copyright (c) 2016, 2018, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -66,24 +66,27 @@ dict_stats_defrag_pool_del(
|
|||||||
all entries for the table */
|
all entries for the table */
|
||||||
const dict_index_t* index); /*!< in: index to remove */
|
const dict_index_t* index); /*!< in: index to remove */
|
||||||
|
|
||||||
/** Process indexes that have been scheduled for defragmenting.
|
/*****************************************************************//**
|
||||||
@param[in,out] trx transaction that will be started and committed */
|
Get the first index that has been added for updating persistent defrag
|
||||||
|
stats and eventually save its stats. */
|
||||||
void
|
void
|
||||||
dict_defrag_process_entries_from_defrag_pool(trx_t* trx);
|
dict_defrag_process_entries_from_defrag_pool();
|
||||||
|
/*===========================================*/
|
||||||
|
|
||||||
/** Save defragmentation result.
|
/*********************************************************************//**
|
||||||
@param[in] index index that was defragmented
|
Save defragmentation result.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save_defrag_summary(dict_index_t* index, trx_t* trx)
|
dict_stats_save_defrag_summary(
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
/*============================*/
|
||||||
|
dict_index_t* index) /*!< in: index */
|
||||||
|
MY_ATTRIBUTE((warn_unused_result));
|
||||||
|
|
||||||
/** Save defragmentation stats for a given index.
|
/*********************************************************************//**
|
||||||
@param[in] index index that is being defragmented
|
Save defragmentation stats for a given index.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save_defrag_stats(dict_index_t* index, trx_t* trx)
|
dict_stats_save_defrag_stats(
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
/*============================*/
|
||||||
|
dict_index_t* index); /*!< in: index */
|
||||||
#endif /* dict0defrag_bg_h */
|
#endif /* dict0defrag_bg_h */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, MariaDB Corporation.
|
Copyright (c) 2017, 2018, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -92,12 +92,13 @@ bool
|
|||||||
dict_stats_auto_recalc_is_enabled(const dict_table_t* table)
|
dict_stats_auto_recalc_is_enabled(const dict_table_t* table)
|
||||||
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
MY_ATTRIBUTE((nonnull, warn_unused_result));
|
||||||
|
|
||||||
/** Initialize table statistics for the first time when opening a table.
|
/*********************************************************************//**
|
||||||
@param[in,out] table freshly opened table
|
Initialize table's stats for the first time when opening a table. */
|
||||||
@param[in,out] trx transaction */
|
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
void
|
void
|
||||||
dict_stats_init(dict_table_t* table, trx_t* trx);
|
dict_stats_init(
|
||||||
|
/*============*/
|
||||||
|
dict_table_t* table); /*!< in/out: table */
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
Deinitialize table's stats after the last close of the table. This is
|
Deinitialize table's stats after the last close of the table. This is
|
||||||
@ -116,68 +117,67 @@ void
|
|||||||
dict_stats_update_if_needed(dict_table_t* table)
|
dict_stats_update_if_needed(dict_table_t* table)
|
||||||
MY_ATTRIBUTE((nonnull));
|
MY_ATTRIBUTE((nonnull));
|
||||||
|
|
||||||
/** Calculate new estimates for table and index statistics.
|
/*********************************************************************//**
|
||||||
@param[in,out] table table
|
Calculates new estimates for table and index statistics. The statistics
|
||||||
@param[in] stats_upd_option how to update statistics
|
are used in query optimization.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_* error code or DB_SUCCESS */
|
@return DB_* error code or DB_SUCCESS */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_update(
|
dict_stats_update(
|
||||||
dict_table_t* table,
|
/*==============*/
|
||||||
dict_stats_upd_option_t stats_upd_option,
|
dict_table_t* table, /*!< in/out: table */
|
||||||
trx_t* trx);
|
dict_stats_upd_option_t stats_upd_option);
|
||||||
|
/*!< in: whether to (re) calc
|
||||||
|
the stats or to fetch them from
|
||||||
|
the persistent storage */
|
||||||
|
|
||||||
/** Remove the persistent statistics for an index.
|
/*********************************************************************//**
|
||||||
@param[in] db_and_table schema and table name, e.g., 'db/table'
|
Removes the information for a particular index's stats from the persistent
|
||||||
@param[in] iname index name
|
storage if it exists and if there is data stored for this index.
|
||||||
@param[out] errstr error message (when not returning DB_SUCCESS)
|
This function creates its own trx and commits it.
|
||||||
@param[in] errstr_sz sizeof errstr
|
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_drop_index(
|
dict_stats_drop_index(
|
||||||
const char* db_and_table,
|
/*==================*/
|
||||||
const char* iname,
|
const char* tname, /*!< in: table name */
|
||||||
char* errstr,
|
const char* iname, /*!< in: index name */
|
||||||
size_t errstr_sz,
|
char* errstr, /*!< out: error message if != DB_SUCCESS
|
||||||
trx_t* trx);
|
is returned */
|
||||||
|
ulint errstr_sz);/*!< in: size of the errstr buffer */
|
||||||
|
|
||||||
/** 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'
|
Removes the statistics for a table and all of its indexes from the
|
||||||
@param[out] errstr error message (when not returning DB_SUCCESS)
|
persistent storage if it exists and if there is data stored for the table.
|
||||||
@param[in] errstr_sz sizeof errstr
|
This function creates its own transaction and commits it.
|
||||||
@param[in,out] trx transaction
|
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_drop_table(
|
dict_stats_drop_table(
|
||||||
const char* db_and_table,
|
/*==================*/
|
||||||
char* errstr,
|
const char* table_name, /*!< in: table name */
|
||||||
size_t errstr_sz,
|
char* errstr, /*!< out: error message
|
||||||
trx_t* trx);
|
if != DB_SUCCESS is returned */
|
||||||
|
ulint errstr_sz); /*!< in: size of errstr buffer */
|
||||||
|
|
||||||
/** Calculate index statistics.
|
/*********************************************************************//**
|
||||||
@param[in,out] index index tree
|
Fetches or calculates new estimates for index statistics. */
|
||||||
@param[in,out] trx transaction (for persistent statistics)
|
void
|
||||||
@return DB_SUCCESS or error code */
|
dict_stats_update_for_index(
|
||||||
UNIV_INTERN
|
/*========================*/
|
||||||
dberr_t
|
dict_index_t* index) /*!< in/out: index */
|
||||||
dict_stats_update_for_index(dict_index_t* index, trx_t* trx)
|
|
||||||
MY_ATTRIBUTE((nonnull));
|
MY_ATTRIBUTE((nonnull));
|
||||||
|
|
||||||
/** Rename a table in the InnoDB persistent statistics storage.
|
/*********************************************************************//**
|
||||||
@param[in] old_name old schema and table name, e.g., 'db/table'
|
Renames a table in InnoDB persistent stats storage.
|
||||||
@param[in] new_name new schema and table name, e.g., 'db/table'
|
This function creates its own transaction and commits it.
|
||||||
@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 */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_rename_table(
|
dict_stats_rename_table(
|
||||||
const char* old_name,
|
/*====================*/
|
||||||
const char* new_name,
|
const char* old_name, /*!< in: old table name */
|
||||||
char* errstr,
|
const char* new_name, /*!< in: new table name */
|
||||||
size_t errstr_sz,
|
char* errstr, /*!< out: error string if != DB_SUCCESS
|
||||||
trx_t* trx);
|
is returned */
|
||||||
|
size_t errstr_sz); /*!< in: errstr size */
|
||||||
|
#ifdef MYSQL_RENAME_INDEX
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
Renames an index in InnoDB persistent stats storage.
|
Renames an index in InnoDB persistent stats storage.
|
||||||
This function creates its own transaction and commits it.
|
This function creates its own transaction and commits it.
|
||||||
@ -191,13 +191,7 @@ dict_stats_rename_index(
|
|||||||
const char* old_index_name, /*!< in: old index name */
|
const char* old_index_name, /*!< in: old index name */
|
||||||
const char* new_index_name) /*!< in: new index name */
|
const char* new_index_name) /*!< in: new index name */
|
||||||
__attribute__((warn_unused_result));
|
__attribute__((warn_unused_result));
|
||||||
|
#endif /* MYSQL_RENAME_INDEX */
|
||||||
/** 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, bool empty_defrag_stats = true);
|
|
||||||
|
|
||||||
/** Save an individual index's statistic into the persistent statistics
|
/** Save an individual index's statistic into the persistent statistics
|
||||||
storage.
|
storage.
|
||||||
@ -207,7 +201,9 @@ storage.
|
|||||||
@param[in] stat_value value of the stat
|
@param[in] stat_value value of the stat
|
||||||
@param[in] sample_size n pages sampled or NULL
|
@param[in] sample_size n pages sampled or NULL
|
||||||
@param[in] stat_description description of the stat
|
@param[in] stat_description description of the stat
|
||||||
@param[in,out] trx dictionary transaction
|
@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.
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
dberr_t
|
dberr_t
|
||||||
dict_stats_save_index_stat(
|
dict_stats_save_index_stat(
|
||||||
@ -217,8 +213,7 @@ dict_stats_save_index_stat(
|
|||||||
ib_uint64_t stat_value,
|
ib_uint64_t stat_value,
|
||||||
ib_uint64_t* sample_size,
|
ib_uint64_t* sample_size,
|
||||||
const char* stat_description,
|
const char* stat_description,
|
||||||
trx_t* trx)
|
trx_t* trx);
|
||||||
MY_ATTRIBUTE((nonnull(1,3,7), warn_unused_result));
|
|
||||||
|
|
||||||
/** Report an error if updating table statistics failed because
|
/** Report an error if updating table statistics failed because
|
||||||
.ibd file is missing, table decryption failed or table is corrupted.
|
.ibd file is missing, table decryption failed or table is corrupted.
|
||||||
|
@ -141,12 +141,13 @@ dict_stats_auto_recalc_is_enabled(const dict_table_t* table)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize table statistics for the first time when opening a table.
|
/*********************************************************************//**
|
||||||
@param[in,out] table freshly opened table
|
Initialize table's stats for the first time when opening a table. */
|
||||||
@param[in,out] trx transaction */
|
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
void
|
void
|
||||||
dict_stats_init(dict_table_t* table, trx_t* trx)
|
dict_stats_init(
|
||||||
|
/*============*/
|
||||||
|
dict_table_t* table) /*!< in/out: table */
|
||||||
{
|
{
|
||||||
ut_ad(!mutex_own(&dict_sys->mutex));
|
ut_ad(!mutex_own(&dict_sys->mutex));
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ dict_stats_init(dict_table_t* table, trx_t* trx)
|
|||||||
opt = DICT_STATS_RECALC_TRANSIENT;
|
opt = DICT_STATS_RECALC_TRANSIENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_stats_update(table, opt, trx);
|
dict_stats_update(table, opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
|
@ -1123,9 +1123,6 @@ struct trx_t {
|
|||||||
mysql_trx_list; /*!< list of transactions created for
|
mysql_trx_list; /*!< list of transactions created for
|
||||||
MySQL; protected by trx_sys->mutex */
|
MySQL; protected by trx_sys->mutex */
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
/** whether this transaction is updating persistent statistics
|
|
||||||
(used for silencing a debug assertion at shutdown) */
|
|
||||||
bool persistent_stats;
|
|
||||||
bool in_mysql_trx_list;
|
bool in_mysql_trx_list;
|
||||||
/*!< true if in
|
/*!< true if in
|
||||||
trx_sys->mysql_trx_list */
|
trx_sys->mysql_trx_list */
|
||||||
|
@ -1683,7 +1683,18 @@ RecLock::prepare() const
|
|||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(trx_get_dict_operation(m_trx) == TRX_DICT_OP_NONE);
|
switch (trx_get_dict_operation(m_trx)) {
|
||||||
|
case TRX_DICT_OP_NONE:
|
||||||
|
break;
|
||||||
|
case TRX_DICT_OP_TABLE:
|
||||||
|
case TRX_DICT_OP_INDEX:
|
||||||
|
ib::error() << "A record lock wait happens in a dictionary"
|
||||||
|
" operation. index " << m_index->name
|
||||||
|
<< " of table " << m_index->table->name
|
||||||
|
<< ". " << BUG_REPORT_MSG;
|
||||||
|
ut_ad(0);
|
||||||
|
}
|
||||||
|
|
||||||
ut_ad(m_index->table->n_ref_count > 0
|
ut_ad(m_index->table->n_ref_count > 0
|
||||||
|| !m_index->table->can_be_evicted);
|
|| !m_index->table->can_be_evicted);
|
||||||
}
|
}
|
||||||
@ -2246,24 +2257,6 @@ RecLock::add_to_waitq(lock_t* wait_for, const lock_prdt_t* prdt)
|
|||||||
|
|
||||||
/* Do the preliminary checks, and set query thread state */
|
/* Do the preliminary checks, and set query thread state */
|
||||||
|
|
||||||
switch (UNIV_EXPECT(trx_get_dict_operation(m_trx), TRX_DICT_OP_NONE)) {
|
|
||||||
case TRX_DICT_OP_NONE:
|
|
||||||
break;
|
|
||||||
case TRX_DICT_OP_TABLE:
|
|
||||||
case TRX_DICT_OP_INDEX:
|
|
||||||
ut_ad(!prdt);
|
|
||||||
|
|
||||||
if (m_trx->dict_operation_lock_mode != RW_X_LATCH) {
|
|
||||||
} else if (!strcmp(m_index->table->name.m_name,
|
|
||||||
"mysql/innodb_table_stats")
|
|
||||||
|| !strcmp(m_index->table->name.m_name,
|
|
||||||
"mysql/innodb_index_stats")) {
|
|
||||||
/* Statistics can be updated as part of a DDL
|
|
||||||
transaction, but only as the very last operation. */
|
|
||||||
return(DB_QUE_THR_SUSPENDED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare();
|
prepare();
|
||||||
|
|
||||||
bool high_priority = trx_is_high_priority(m_trx);
|
bool high_priority = trx_is_high_priority(m_trx);
|
||||||
@ -4664,16 +4657,6 @@ lock_table_enqueue_waiting(
|
|||||||
break;
|
break;
|
||||||
case TRX_DICT_OP_TABLE:
|
case TRX_DICT_OP_TABLE:
|
||||||
case TRX_DICT_OP_INDEX:
|
case TRX_DICT_OP_INDEX:
|
||||||
if (trx->dict_operation_lock_mode != RW_X_LATCH) {
|
|
||||||
} else if (!strcmp(table->name.m_name,
|
|
||||||
"mysql/innodb_table_stats")
|
|
||||||
|| !strcmp(table->name.m_name,
|
|
||||||
"mysql/innodb_index_stats")) {
|
|
||||||
/* Statistics can be updated as part of a DDL
|
|
||||||
transaction, but only as the very last operation. */
|
|
||||||
return(DB_QUE_THR_SUSPENDED);
|
|
||||||
}
|
|
||||||
|
|
||||||
ib::error() << "A table lock wait happens in a dictionary"
|
ib::error() << "A table lock wait happens in a dictionary"
|
||||||
" operation. Table " << table->name
|
" operation. Table " << table->name
|
||||||
<< ". " << BUG_REPORT_MSG;
|
<< ". " << BUG_REPORT_MSG;
|
||||||
|
@ -3289,9 +3289,31 @@ run_again:
|
|||||||
que_thr_stop_for_mysql_no_error(thr, trx);
|
que_thr_stop_for_mysql_no_error(thr, trx);
|
||||||
} else {
|
} else {
|
||||||
que_thr_stop_for_mysql(thr);
|
que_thr_stop_for_mysql(thr);
|
||||||
ut_ad(err != DB_QUE_THR_SUSPENDED);
|
|
||||||
|
|
||||||
if (row_mysql_handle_errors(&err, trx, thr, NULL)) {
|
if (err != DB_QUE_THR_SUSPENDED) {
|
||||||
|
ibool was_lock_wait;
|
||||||
|
|
||||||
|
was_lock_wait = row_mysql_handle_errors(
|
||||||
|
&err, trx, thr, NULL);
|
||||||
|
|
||||||
|
if (was_lock_wait) {
|
||||||
|
goto run_again;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
que_thr_t* run_thr;
|
||||||
|
que_node_t* parent;
|
||||||
|
|
||||||
|
parent = que_node_get_parent(thr);
|
||||||
|
|
||||||
|
run_thr = que_fork_start_command(
|
||||||
|
static_cast<que_fork_t*>(parent));
|
||||||
|
|
||||||
|
ut_a(run_thr == thr);
|
||||||
|
|
||||||
|
/* There was a lock wait but the thread was not
|
||||||
|
in a ready to run or running state. */
|
||||||
|
trx->error_state = DB_LOCK_WAIT;
|
||||||
|
|
||||||
goto run_again;
|
goto run_again;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3569,6 +3591,7 @@ row_drop_table_for_mysql(
|
|||||||
|
|
||||||
if (!dict_table_is_temporary(table)) {
|
if (!dict_table_is_temporary(table)) {
|
||||||
|
|
||||||
|
dict_stats_recalc_pool_del(table);
|
||||||
dict_stats_defrag_pool_del(table, NULL);
|
dict_stats_defrag_pool_del(table, NULL);
|
||||||
if (btr_defragment_thread_active) {
|
if (btr_defragment_thread_active) {
|
||||||
/* During fts_drop_orphaned_tables() in
|
/* During fts_drop_orphaned_tables() in
|
||||||
@ -3577,6 +3600,17 @@ row_drop_table_for_mysql(
|
|||||||
initialized by btr_defragment_init(). */
|
initialized by btr_defragment_init(). */
|
||||||
btr_defragment_remove_table(table);
|
btr_defragment_remove_table(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove stats for this table and all of its indexes from the
|
||||||
|
persistent storage if it exists and if there are stats for this
|
||||||
|
table in there. This function creates its own trx and commits
|
||||||
|
it. */
|
||||||
|
char errstr[1024];
|
||||||
|
err = dict_stats_drop_table(name, errstr, sizeof(errstr));
|
||||||
|
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
ib::warn() << errstr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_table_prevent_eviction(table);
|
dict_table_prevent_eviction(table);
|
||||||
@ -3894,20 +3928,9 @@ row_drop_table_for_mysql(
|
|||||||
table_flags = table->flags;
|
table_flags = table->flags;
|
||||||
ut_ad(!dict_table_is_temporary(table));
|
ut_ad(!dict_table_is_temporary(table));
|
||||||
|
|
||||||
#if MYSQL_VERSION_ID >= 100300
|
err = row_drop_ancillary_fts_tables(table, trx);
|
||||||
if (!table->no_rollback())
|
if (err != DB_SUCCESS) {
|
||||||
#endif
|
break;
|
||||||
{
|
|
||||||
char errstr[1024];
|
|
||||||
if (dict_stats_drop_table(name, errstr, sizeof errstr,
|
|
||||||
trx) != DB_SUCCESS) {
|
|
||||||
ib::warn() << errstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = row_drop_ancillary_fts_tables(table, trx);
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the tablespace filename before we drop
|
/* Determine the tablespace filename before we drop
|
||||||
|
@ -1271,6 +1271,10 @@ row_truncate_complete(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (err == DB_SUCCESS) {
|
||||||
|
dict_stats_update(table, DICT_STATS_EMPTY_TABLE);
|
||||||
|
}
|
||||||
|
|
||||||
trx->op_info = "";
|
trx->op_info = "";
|
||||||
|
|
||||||
/* For temporary tables or if there was an error, we need to reset
|
/* For temporary tables or if there was an error, we need to reset
|
||||||
@ -2103,17 +2107,8 @@ row_truncate_table_for_mysql(
|
|||||||
dict_table_autoinc_unlock(table);
|
dict_table_autoinc_unlock(table);
|
||||||
|
|
||||||
if (trx_is_started(trx)) {
|
if (trx_is_started(trx)) {
|
||||||
char errstr[1024];
|
|
||||||
if (dict_stats_drop_table(table->name.m_name, errstr,
|
|
||||||
sizeof errstr, trx) != DB_SUCCESS) {
|
|
||||||
ib::warn() << "Deleting persistent "
|
|
||||||
"statistics for table " << table->name
|
|
||||||
<< " failed: " << errstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
|
|
||||||
dict_stats_empty_table(table);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(row_truncate_complete(table, trx, fsp_flags, logger, err));
|
return(row_truncate_complete(table, trx, fsp_flags, logger, err));
|
||||||
|
@ -302,7 +302,7 @@ trx_purge_add_update_undo_to_history(
|
|||||||
|| (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND
|
|| (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND
|
||||||
&& purge_sys->state == PURGE_STATE_DISABLED)
|
&& purge_sys->state == PURGE_STATE_DISABLED)
|
||||||
|| ((trx->undo_no == 0 || trx->in_mysql_trx_list
|
|| ((trx->undo_no == 0 || trx->in_mysql_trx_list
|
||||||
|| trx->persistent_stats)
|
|| trx->internal)
|
||||||
&& srv_fast_shutdown));
|
&& srv_fast_shutdown));
|
||||||
|
|
||||||
/* Add the log as the first in the history list */
|
/* Add the log as the first in the history list */
|
||||||
|
@ -553,7 +553,7 @@ trx_validate_state_before_free(trx_t* trx)
|
|||||||
ut_ad(!trx->declared_to_be_inside_innodb);
|
ut_ad(!trx->declared_to_be_inside_innodb);
|
||||||
ut_ad(!trx->n_mysql_tables_in_use);
|
ut_ad(!trx->n_mysql_tables_in_use);
|
||||||
ut_ad(!trx->mysql_n_tables_locked);
|
ut_ad(!trx->mysql_n_tables_locked);
|
||||||
ut_ad(!trx->persistent_stats);
|
ut_ad(!trx->internal);
|
||||||
|
|
||||||
if (trx->declared_to_be_inside_innodb) {
|
if (trx->declared_to_be_inside_innodb) {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user