commit 8545447decb54e4f8c54949b809aa2238892f261 Author: Zsolt Parragi Date: Thu May 24 10:01:09 2018 +0200 Fix bug 90351 / PS-3951 (Fix decreasing status counters) Status counters were cleaned in THD::release_resources, before an optional thread cleanup. The cleanup could possibly perform a rollback, or other counter-increasing operations. In this case, these additions to the thread local counters were lost during the destruction of the thread, but were visible for a short time, before the thread was removed from the global thread list. This change avoids this issue by moving the global counter update to the end of the release_resources method, ensuring that possible counter-changing operation happen before it. diff --git a/mysql-test/r/bug90351.result b/mysql-test/r/bug90351.result new file mode 100644 index 00000000000..0546793fd97 --- /dev/null +++ b/mysql-test/r/bug90351.result @@ -0,0 +1,6 @@ +CREATE TABLE t1 (i INTEGER); +INSERT INTO t1 VALUES (1); +SET AUTOCOMMIT=0; +START TRANSACTION; +DELETE FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/bug90351.test b/mysql-test/t/bug90351.test new file mode 100644 index 00000000000..42a9d1d8fbd --- /dev/null +++ b/mysql-test/t/bug90351.test @@ -0,0 +1,25 @@ +# +# Bug 90351: status counters decrease on thread destruction +# +--source include/count_sessions.inc + +connect (con1,localhost,root,,); + +connection con1; +CREATE TABLE t1 (i INTEGER); +INSERT INTO t1 VALUES (1); +let $con1_id= `SELECT connection_id()`; +SET AUTOCOMMIT=0; +START TRANSACTION; +DELETE FROM t1; + +connection default; +--disable_query_log +eval KILL $con1_id; +--enable_query_log + +connection default; +DROP TABLE t1; + +disconnect con1; +--source include/wait_until_count_sessions.inc diff --git a/sql/handler.cc b/sql/handler.cc index 0e54fba63ed..0f0fec26672 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1347,6 +1347,7 @@ int ha_prepare(THD *thd) { while (ha_info) { handlerton *ht = ha_info->ht(); + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_prepare_count++; if (ht->prepare) { DBUG_EXECUTE_IF("simulate_xa_failure_prepare", { @@ -1809,6 +1810,7 @@ int ha_commit_low(THD *thd, bool all, bool run_after_commit) { my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_commit_count++; ha_info_next = ha_info->next(); if (restore_backup_ha_data) reattach_engine_ha_data_to_thd(thd, ht); @@ -1869,6 +1871,7 @@ int ha_rollback_low(THD *thd, bool all) { my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_rollback_count++; ha_info_next = ha_info->next(); if (restore_backup_ha_data) reattach_engine_ha_data_to_thd(thd, ht); @@ -2031,6 +2034,7 @@ int ha_commit_attachable(THD *thd) { DBUG_ASSERT(false); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_commit_count++; ha_info_next = ha_info->next(); @@ -2119,6 +2123,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_savepoint_rollback_count++; if (ht->prepare == 0) trn_ctx->set_no_2pc(trx_scope, true); } @@ -2137,6 +2142,7 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) { my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_rollback_count++; ha_info_next = ha_info->next(); ha_info->reset(); /* keep it conveniently zero-filled */ @@ -2175,6 +2181,7 @@ int ha_prepare_low(THD *thd, bool all) { my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_prepare_count++; } DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE();); @@ -2215,6 +2222,7 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) { my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err)); error = 1; } + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.ha_savepoint_count++; } /* @@ -2529,6 +2537,7 @@ err: void handler::ha_statistic_increment( ulonglong System_status_var::*offset) const { + DBUG_ASSERT(!table->in_use->status_var_aggregated); (table->in_use->status_var.*offset)++; } @@ -5300,7 +5309,10 @@ static int ha_discover(THD *thd, const char *db, const char *name, &args)) error = 0; - if (!error) thd->status_var.ha_discover_count++; + if (!error) { + DBUG_ASSERT(!thd->status_var_aggregated); + thd->status_var.ha_discover_count++; + } DBUG_RETURN(error); } @@ -6134,7 +6146,10 @@ int DsMrr_impl::dsmrr_init(RANGE_SEQ_IF *seq_funcs, void *seq_init_param, is_mrr_assoc = !(mode & HA_MRR_NO_ASSOCIATION); - if (is_mrr_assoc) table->in_use->status_var.ha_multi_range_read_init_count++; + if (is_mrr_assoc) { + DBUG_ASSERT(!thd->status_var_aggregated); + table->in_use->status_var.ha_multi_range_read_init_count++; + } rowids_buf_end = buf->buffer_end; elem_size = h->ref_length + (int)is_mrr_assoc * sizeof(void *); diff --git a/sql/rpl_master.cc b/sql/rpl_master.cc index db9e1984221..bd26f6b8ed8 100644 --- a/sql/rpl_master.cc +++ b/sql/rpl_master.cc @@ -650,6 +650,7 @@ bool com_binlog_dump(THD *thd, char *packet, size_t packet_length) { const uchar *packet_position = (uchar *)packet; size_t packet_bytes_todo = packet_length; + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.com_other++; thd->enable_slow_log = opt_log_slow_admin_statements; if (check_global_access(thd, REPL_SLAVE_ACL)) DBUG_RETURN(false); @@ -700,6 +701,7 @@ bool com_binlog_dump_gtid(THD *thd, char *packet, size_t packet_length) { NULL /*no sid_lock because this is a completely local object*/); Gtid_set slave_gtid_executed(&sid_map); + DBUG_ASSERT(!thd->status_var_aggregated); thd->status_var.com_other++; thd->enable_slow_log = opt_log_slow_admin_statements; if (check_global_access(thd, REPL_SLAVE_ACL)) DBUG_RETURN(false); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 13ab695841c..d13f7b90a2d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -969,18 +969,6 @@ void THD::release_resources() { Global_THD_manager::get_instance()->release_thread_id(m_thread_id); - mysql_mutex_lock(&LOCK_status); - add_to_status(&global_status_var, &status_var, false); - /* - Status queries after this point should not aggregate THD::status_var - since the values has been added to global_status_var. - The status values are not reset so that they can still be read - by performance schema. - */ - status_var_aggregated = true; - - mysql_mutex_unlock(&LOCK_status); - /* Ensure that no one is using THD */ mysql_mutex_lock(&LOCK_thd_data); mysql_mutex_lock(&LOCK_query_plan); @@ -1028,6 +1016,18 @@ void THD::release_resources() { if (current_thd == this) restore_globals(); + mysql_mutex_lock(&LOCK_status); + add_to_status(&global_status_var, &status_var, false); + /* + Status queries after this point should not aggregate THD::status_var + since the values has been added to global_status_var. + The status values are not reset so that they can still be read + by performance schema. + */ + status_var_aggregated = true; + + mysql_mutex_unlock(&LOCK_status); + m_release_resources_done = true; } @@ -1165,7 +1165,10 @@ void THD::awake(THD::killed_state state_to_set) { if (state_to_set != THD::NOT_KILLED) ha_kill_connection(this); if (state_to_set == THD::KILL_TIMEOUT) + { + DBUG_ASSERT(!status_var_aggregated); status_var.max_execution_time_exceeded++; + } /* Broadcast a condition to kick the target if it is waiting on it. */ if (is_killable) { @@ -2065,6 +2068,7 @@ void THD::inc_examined_row_count(ha_rows count) { } void THD::inc_status_created_tmp_disk_tables() { + DBUG_ASSERT(!status_var_aggregated); status_var.created_tmp_disk_tables++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_created_tmp_disk_tables)(m_statement_psi, 1); @@ -2072,6 +2076,7 @@ void THD::inc_status_created_tmp_disk_tables() { } void THD::inc_status_created_tmp_tables() { + DBUG_ASSERT(!status_var_aggregated); status_var.created_tmp_tables++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_created_tmp_tables)(m_statement_psi, 1); @@ -2079,6 +2084,7 @@ void THD::inc_status_created_tmp_tables() { } void THD::inc_status_select_full_join() { + DBUG_ASSERT(!status_var_aggregated); status_var.select_full_join_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_select_full_join)(m_statement_psi, 1); @@ -2086,6 +2092,7 @@ void THD::inc_status_select_full_join() { } void THD::inc_status_select_full_range_join() { + DBUG_ASSERT(!status_var_aggregated); status_var.select_full_range_join_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_select_full_range_join)(m_statement_psi, 1); @@ -2093,6 +2100,7 @@ void THD::inc_status_select_full_range_join() { } void THD::inc_status_select_range() { + DBUG_ASSERT(!status_var_aggregated); status_var.select_range_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_select_range)(m_statement_psi, 1); @@ -2100,6 +2108,7 @@ void THD::inc_status_select_range() { } void THD::inc_status_select_range_check() { + DBUG_ASSERT(!status_var_aggregated); status_var.select_range_check_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_select_range_check)(m_statement_psi, 1); @@ -2107,6 +2116,7 @@ void THD::inc_status_select_range_check() { } void THD::inc_status_select_scan() { + DBUG_ASSERT(!status_var_aggregated); status_var.select_scan_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_select_scan)(m_statement_psi, 1); @@ -2114,6 +2124,7 @@ void THD::inc_status_select_scan() { } void THD::inc_status_sort_merge_passes() { + DBUG_ASSERT(!status_var_aggregated); status_var.filesort_merge_passes++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_sort_merge_passes)(m_statement_psi, 1); @@ -2121,6 +2132,7 @@ void THD::inc_status_sort_merge_passes() { } void THD::inc_status_sort_range() { + DBUG_ASSERT(!status_var_aggregated); status_var.filesort_range_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_sort_range)(m_statement_psi, 1); @@ -2128,6 +2140,7 @@ void THD::inc_status_sort_range() { } void THD::inc_status_sort_rows(ha_rows count) { + DBUG_ASSERT(!status_var_aggregated); status_var.filesort_rows += count; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_sort_rows) @@ -2136,6 +2149,7 @@ void THD::inc_status_sort_rows(ha_rows count) { } void THD::inc_status_sort_scan() { + DBUG_ASSERT(!status_var_aggregated); status_var.filesort_scan_count++; #ifdef HAVE_PSI_STATEMENT_INTERFACE PSI_STATEMENT_CALL(inc_statement_sort_scan)(m_statement_psi, 1); diff --git a/sql/sql_class.h b/sql/sql_class.h index d4ae7eac69c..a98e439f6f9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -951,6 +951,7 @@ class THD : public MDL_context_owner, actually reports the previous query, not itself. */ void save_current_query_costs() { + DBUG_ASSERT(!status_var_aggregated); status_var.last_query_cost = m_current_query_cost; status_var.last_query_partial_plans = m_current_query_partial_plans; }