commit 98a52a3e363c86fbbd60f94b157f4fd27edc58ac Author: xpchild Date: Wed Dec 25 20:23:18 2019 +0800 [Perf] Wakeup follower one by one when group commit Summary: -------- When group commit, leader will wake up followers through broadcast, but if the follower wait for other leader, it will wait again. so here optimize the logic by waking up one by one. it can improve the write performance. diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 3f179a7a5b0..2b1eb50319c 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -546,6 +546,7 @@ SET(SQL_SHARED_SOURCES uniques.cc xa.cc ssl_acceptor_context.cc + commit_state.cc ${MYSQL_SERVER_SUB_COMPONENT_SOURCES} ) diff --git a/sql/binlog.cc b/sql/binlog.cc index f3d8f226cc1..7cf364f4049 100644 --- a/sql/binlog.cc +++ b/sql/binlog.cc @@ -123,6 +123,7 @@ #include "sql/xa.h" #include "sql_partition.h" #include "thr_lock.h" +#include "sql/commit_state.h" class Item; @@ -2332,8 +2333,8 @@ bool Stage_manager::enroll_for(StageID stage, THD *thd, to release it before going to sleep. */ if (!leader) { - mysql_mutex_lock(&m_lock_done); #ifndef DBUG_OFF + mysql_mutex_lock(&m_lock_done); /* Leader can be awaiting all-clear to preempt follower's execution. With setting the status the follower ensures it won't execute anything @@ -2341,9 +2342,9 @@ bool Stage_manager::enroll_for(StageID stage, THD *thd, */ thd->get_transaction()->m_flags.ready_preempt = 1; if (leader_await_preempt_status) mysql_cond_signal(&m_cond_preempt); -#endif - while (thd->tx_commit_pending) mysql_cond_wait(&m_cond_done, &m_lock_done); mysql_mutex_unlock(&m_lock_done); +#endif + thd->commit_state()->wait(); } return leader; } @@ -2392,11 +2393,12 @@ void Stage_manager::wait_count_or_timeout(ulong count, long usec, } void Stage_manager::signal_done(THD *queue) { - mysql_mutex_lock(&m_lock_done); - for (THD *thd = queue; thd; thd = thd->next_to_commit) - thd->tx_commit_pending = false; - mysql_mutex_unlock(&m_lock_done); - mysql_cond_broadcast(&m_cond_done); + THD *thd = queue; + while (thd) { + THD *tmp_thd = thd; + thd = thd->next_to_commit; + tmp_thd->commit_state()->signal(); + } } #ifndef DBUG_OFF @@ -8226,7 +8228,7 @@ void MYSQL_BIN_LOG::process_commit_stage_queue(THD *thd, THD *first) { for (THD *head = first; head; head = head->next_to_commit) { DBUG_PRINT("debug", ("Thread ID: %u, commit_error: %d, commit_pending: %s", head->thread_id(), head->commit_error, - YESNO(head->tx_commit_pending))); + YESNO(head->commit_state()->pending()))); DBUG_EXECUTE_IF( "block_leader_after_delete", if (thd != head) { DBUG_SET("+d,after_delete_wait"); };); @@ -8264,7 +8266,7 @@ void MYSQL_BIN_LOG::process_commit_stage_queue(THD *thd, THD *first) { head->commit_error = THD::CE_COMMIT_ERROR; } DBUG_PRINT("debug", ("commit_error: %d, commit_pending: %s", - head->commit_error, YESNO(head->tx_commit_pending))); + head->commit_error, YESNO(head->commit_state()->pending()))); } /* @@ -8684,7 +8686,7 @@ int MYSQL_BIN_LOG::ordered_commit(THD *thd, bool all, bool skip_commit) { - Everything in the transaction structure is reset when calling ha_commit_low since that calls Transaction_ctx::cleanup. */ - thd->tx_commit_pending = true; + thd->commit_state()->enter(); thd->commit_error = THD::CE_NONE; thd->next_to_commit = nullptr; thd->durability_property = HA_IGNORE_DURABILITY; @@ -8705,7 +8707,7 @@ int MYSQL_BIN_LOG::ordered_commit(THD *thd, bool all, bool skip_commit) { #endif DBUG_PRINT("enter", ("commit_pending: %s, commit_error: %d, thread_id: %u", - YESNO(thd->tx_commit_pending), thd->commit_error, + YESNO(thd->commit_state()->pending()), thd->commit_error, thd->thread_id())); DEBUG_SYNC(thd, "bgc_before_flush_stage"); diff --git a/sql/commit_state.cc b/sql/commit_state.cc new file mode 100644 index 00000000000..a40e2599c38 --- /dev/null +++ b/sql/commit_state.cc @@ -0,0 +1,57 @@ +/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "my_config.h" +#include "my_psi_config.h" + +#include "my_macros.h" +#include "mysql/psi/mysql_cond.h" +#include "mysql/psi/mysql_mutex.h" +#include "mysql/psi/psi_base.h" + +#include "sql/commit_state.h" + +Commit_state::Commit_state() : tx_commit_pending(false) { + mysql_mutex_init(key_LOCK_commit_state, &m_mutex, MY_MUTEX_INIT_FAST); + mysql_cond_init(key_COND_commit_state, &m_cond); +} + +Commit_state::~Commit_state() { + mysql_mutex_destroy(&m_mutex); + mysql_cond_destroy(&m_cond); +} + +void Commit_state::enter() { tx_commit_pending = true; } +void Commit_state::reset() { tx_commit_pending = false; } + +void Commit_state::wait() { + mysql_mutex_lock(&m_mutex); + while (tx_commit_pending) + mysql_cond_wait(&m_cond, &m_mutex); + mysql_mutex_unlock(&m_mutex); +} + +void Commit_state::signal() { + mysql_mutex_lock(&m_mutex); + tx_commit_pending = false; + mysql_cond_signal(&m_cond); + mysql_mutex_unlock(&m_mutex); +} diff --git a/sql/commit_state.h b/sql/commit_state.h new file mode 100644 index 00000000000..80f217a69c1 --- /dev/null +++ b/sql/commit_state.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef SQL_COMMIT_STATE_INCLUDED +#define SQL_COMMIT_STATE_INCLUDED + +#include "mysql/components/services/mysql_cond_bits.h" +#include "mysql/components/services/mysql_mutex_bits.h" +#include "mysql/components/services/psi_mutex_bits.h" + +#ifdef HAVE_PSI_INTERFACE +extern PSI_mutex_key key_LOCK_commit_state; +extern PSI_cond_key key_COND_commit_state; +#endif + +class Commit_state { +public: + explicit Commit_state(); + virtual ~Commit_state(); + + void enter(); + void wait(); + void signal(); + void reset(); + + bool pending() { return tx_commit_pending; } + +private: + bool tx_commit_pending; + mysql_mutex_t m_mutex; + mysql_cond_t m_cond; +}; + +#endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 178a572a5aa..07bcb6d407c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -792,6 +792,7 @@ The documentation is based on the source files such as: #include "sql/dd/upgrade_57/upgrade.h" // dd::upgrade_57::in_progress #include "sql/srv_session.h" +#include "sql/commit_state.h" using std::max; using std::min; using std::vector; @@ -10453,6 +10454,8 @@ PSI_mutex_key key_thd_timer_mutex; PSI_mutex_key key_commit_order_manager_mutex; PSI_mutex_key key_mutex_slave_worker_hash; +PSI_mutex_key key_LOCK_commit_state; + /* clang-format off */ static PSI_mutex_info all_server_mutexes[]= { @@ -10539,7 +10542,8 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_password_reuse_interval, "LOCK_password_reuse_interval", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, { &key_LOCK_keyring_operations, "LOCK_keyring_operations", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, { &key_LOCK_tls_ctx_options, "LOCK_tls_ctx_options", 0, 0, "A lock to control all of the --ssl-* CTX related command line options"}, - { &key_LOCK_rotate_binlog_master_key, "LOCK_rotate_binlog_master_key", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME} + { &key_LOCK_rotate_binlog_master_key, "LOCK_rotate_binlog_master_key", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, + { &key_LOCK_commit_state, "Commit_state::m_mutex", 0, PSI_VOLATILITY_SESSION, PSI_DOCUMENT_ME} }; /* clang-format on */ @@ -10610,6 +10614,7 @@ PSI_cond_key key_gtid_ensure_index_cond; PSI_cond_key key_COND_thr_lock; PSI_cond_key key_commit_order_manager_cond; PSI_cond_key key_cond_slave_worker_hash; +PSI_cond_key key_COND_commit_state; /* clang-format off */ static PSI_cond_info all_server_conds[]= @@ -10650,7 +10655,8 @@ static PSI_cond_info all_server_conds[]= { &key_gtid_ensure_index_cond, "Gtid_state", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, { &key_COND_compress_gtid_table, "COND_compress_gtid_table", PSI_FLAG_SINGLETON, 0, PSI_DOCUMENT_ME}, { &key_commit_order_manager_cond, "Commit_order_manager::m_workers.cond", 0, 0, PSI_DOCUMENT_ME}, - { &key_cond_slave_worker_hash, "Relay_log_info::slave_worker_hash_lock", 0, 0, PSI_DOCUMENT_ME} + { &key_cond_slave_worker_hash, "Relay_log_info::slave_worker_hash_lock", 0, 0, PSI_DOCUMENT_ME}, + { &key_COND_commit_state, "Commit_state::m_cond", 0, 0, PSI_DOCUMENT_ME}, }; /* clang-format on */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 83a4d5bd70c..d92e1a6ca86 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -433,7 +433,8 @@ THD::THD(bool enable_plugins) m_stmt_da(&main_da), duplicate_slave_id(false), is_a_srv_session_thd(false), - m_is_plugin_fake_ddl(false) { + m_is_plugin_fake_ddl(false), + m_commit_state(new Commit_state()) { main_lex->reset(); set_psi(NULL); mdl_context.init(this); @@ -475,7 +476,6 @@ THD::THD(bool enable_plugins) binlog_evt_union.do_union = false; enable_slow_log = 0; commit_error = CE_NONE; - tx_commit_pending = false; durability_property = HA_REGULAR_DURABILITY; #ifndef DBUG_OFF dbug_sentry = THD_SENTRY_MAGIC; diff --git a/sql/sql_class.h b/sql/sql_class.h index 0bbae9580af..c98d7f2cd16 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -110,6 +110,8 @@ #include "thr_lock.h" #include "violite.h" +#include "sql/commit_state.h" + enum enum_check_fields : int; enum enum_tx_isolation : int; enum ha_notification_type : int; @@ -899,9 +901,6 @@ class THD : public MDL_context_owner, /* Slave applier execution context */ Relay_log_info *rli_slave; - /* Is transaction commit still pending */ - bool tx_commit_pending; - /** The function checks whether the thread is processing queries from binlog, as automatically generated by mysqlbinlog. @@ -4155,6 +4154,13 @@ class THD : public MDL_context_owner, public: bool is_system_user(); void set_system_user(bool system_user_flag); + + /* Is transaction commit still pending */ + public: + Commit_state *commit_state() { return m_commit_state.get(); } + + private: + std::unique_ptr m_commit_state; }; /** diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 93c5f9b0530..256ec9d5e3f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5068,7 +5068,7 @@ void THD::reset_for_next_command() { thd->want_privilege = ~NO_ACCESS; thd->reset_skip_readonly_check(); - thd->tx_commit_pending = false; + thd->commit_state()->reset(); DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row(): %d", thd->is_current_stmt_binlog_format_row()));