This patch introduces new class atomic_counter which is using relaxed memory order for loads/stores and increments/decrements. The type of following variables is changed to atomic_counter: - atomic_global_query_id, because atomicity is the only requirement, each query should just get its unique id - atomic_global_thd_count, becuase the only use of it is for statics - m_size in Commit_stage_manager::Mutex_queue, because the only reason to use atomics here is to prevent turn reads. Updates are protected with lock()/unlock() Also gtid_mode_counter usage pattern is changed to load-acquire / store-release. This counter is used to signal that the global variable has been changed and we need to update its cached value. It is a perfect case for acquire-release. diff --git a/include/my_atomic.h b/include/my_atomic.h index ce8927816f6..aba2b337852 100644 --- a/include/my_atomic.h +++ b/include/my_atomic.h @@ -27,6 +27,8 @@ @file include/my_atomic.h */ +#include + #if defined(_MSC_VER) #include @@ -60,4 +62,33 @@ static inline int my_yield_processor() { #endif +template +class atomic_counter { + private: + std::atomic m_counter; + + public: + atomic_counter(T n) : m_counter(n) {} + atomic_counter() {} + + T add(T n) { return m_counter.fetch_add(n, std::memory_order_relaxed); } + T sub(T n) { return m_counter.fetch_sub(n, std::memory_order_relaxed); } + T load() const { return m_counter.load(std::memory_order_relaxed); } + void store(T n) { m_counter.store(n, std::memory_order_relaxed); } + + T operator++(int) { return add(1); } + T operator--(int) { return sub(1); } + T operator++() { return add(1) + 1; } + T operator--() { return sub(1) - 1; } + T operator+=(T n) { return add(n) + n; } + T operator-=(T n) { return sub(n) - n; } + + operator T() const { return m_counter.load(); } + + T operator=(T n) { + store(n); + return n; + } +}; + #endif /* MY_ATOMIC_INCLUDED */ diff --git a/sql/mdl.cc b/sql/mdl.cc index 31f3500a09d..8479af7026e 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -29,6 +29,7 @@ #include "lf.h" #include "m_ctype.h" +#include "my_atomic.h" #include "my_dbug.h" #include "my_macros.h" #include "my_murmur3.h" @@ -267,7 +268,7 @@ class MDL_map { for some short period of time. Code which uses its value needs to take this into account. */ - std::atomic m_unused_lock_objects; + atomic_counter m_unused_lock_objects; }; /** diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 85b93bbf97e..9fcd41eacce 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1165,7 +1165,7 @@ long opt_binlog_group_commit_sync_delay = 0; ulong opt_binlog_group_commit_sync_no_delay_count = 0; ulonglong max_binlog_stmt_cache_size = 0; ulong refresh_version; /* Increments on each reload */ -std::atomic atomic_global_query_id{1}; +atomic_counter atomic_global_query_id{1}; ulong aborted_threads; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; diff --git a/sql/mysqld.h b/sql/mysqld.h index 9ec03463956..c3917bb441a 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -35,6 +35,7 @@ #include #include "lex_string.h" #include "m_ctype.h" +#include "my_atomic.h" #include "my_command.h" #include "my_compiler.h" #include "my_compress.h" @@ -693,7 +694,7 @@ extern char *opt_disabled_storage_engines; extern sigset_t mysqld_signal_mask; /* query_id */ typedef int64 query_id_t; -extern std::atomic atomic_global_query_id; +extern atomic_counter atomic_global_query_id; int *get_remaining_argc(); char ***get_remaining_argv(); diff --git a/sql/mysqld_thd_manager.cc b/sql/mysqld_thd_manager.cc index a477953b6cc..180ada99302 100644 --- a/sql/mysqld_thd_manager.cc +++ b/sql/mysqld_thd_manager.cc @@ -38,6 +38,7 @@ #include #include "mutex_lock.h" // MUTEX_LOCK +#include "my_atomic.h" #include "my_command.h" #include "my_compiler.h" #include "my_dbug.h" @@ -49,7 +50,7 @@ #include "sql/sql_class.h" // THD #include "thr_mutex.h" -std::atomic Global_THD_manager::atomic_global_thd_count{0U}; +atomic_counter Global_THD_manager::atomic_global_thd_count{0U}; Global_THD_manager *Global_THD_manager::thd_manager = nullptr; static inline int thd_partition(my_thread_id thread_id) { diff --git a/sql/mysqld_thd_manager.h b/sql/mysqld_thd_manager.h index bf04e6b623f..3b430b777d1 100644 --- a/sql/mysqld_thd_manager.h +++ b/sql/mysqld_thd_manager.h @@ -27,6 +27,7 @@ #include #include +#include "my_atomic.h" #include "my_dbug.h" #include "my_inttypes.h" #include "my_thread_local.h" // my_thread_id @@ -238,7 +239,7 @@ class Global_THD_manager { THD *find_thd(Find_thd_with_id *func); // Declared static as it is referenced in handle_fatal_signal() - static std::atomic atomic_global_thd_count; + static atomic_counter atomic_global_thd_count; // Number of THD list partitions. static const int NUM_PARTITIONS = 8; @@ -271,7 +272,7 @@ class Global_THD_manager { std::atomic atomic_num_thread_running; // Cumulative number of threads created by mysqld daemon. - std::atomic atomic_thread_created; + atomic_counter atomic_thread_created; // Counter to assign thread id. my_thread_id thread_id_counter; diff --git a/sql/rpl_commit_stage_manager.cc b/sql/rpl_commit_stage_manager.cc index a353a214886..8dacf4364ae 100644 --- a/sql/rpl_commit_stage_manager.cc +++ b/sql/rpl_commit_stage_manager.cc @@ -56,7 +56,7 @@ bool Commit_stage_manager::Mutex_queue::append(THD *first) { count++; first = first->next_to_commit; } - m_size += count; + m_size = m_size + count; m_last = &first->next_to_commit; DBUG_PRINT("info", @@ -84,7 +84,7 @@ std::pair Commit_stage_manager::Mutex_queue::pop_front() { m_last = &m_first; } DBUG_ASSERT(m_size.load() > 0); - --m_size; + m_size = m_size - 1; DBUG_ASSERT(m_first || m_last == &m_first); unlock(); DBUG_PRINT("return", diff --git a/sql/rpl_commit_stage_manager.h b/sql/rpl_commit_stage_manager.h index b69d71bf8af..343296e2bee 100644 --- a/sql/rpl_commit_stage_manager.h +++ b/sql/rpl_commit_stage_manager.h @@ -26,6 +26,7 @@ #include #include +#include "my_atomic.h" #include "my_dbug.h" #include "mysql/psi/mysql_cond.h" #include "mysql/psi/mysql_mutex.h" @@ -133,7 +134,7 @@ class Commit_stage_manager { THD **m_last; /** size of the queue */ - std::atomic m_size; + atomic_counter m_size; /** Lock for protecting the queue. */ mysql_mutex_t *m_lock; diff --git a/sql/rpl_gtid.h b/sql/rpl_gtid.h index 5776bc09d14..2ef55466a13 100644 --- a/sql/rpl_gtid.h +++ b/sql/rpl_gtid.h @@ -3906,7 +3906,8 @@ class Gtid_mode_copy { @param have_lock The lock type held by the caller. */ enum_gtid_mode get_gtid_mode_from_copy(enum_gtid_mode_lock have_lock) { - ulong current_gtid_mode_counter = gtid_mode_counter; + ulong current_gtid_mode_counter = + gtid_mode_counter.load(std::memory_order_acquire); // Update out copy of GTID_MODE if needed if (m_gtid_mode_counter != current_gtid_mode_counter) { m_gtid_mode = get_gtid_mode(have_lock); diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index bf05e65d6b0..334bc5ed073 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -43,6 +43,7 @@ #include "libbinlogevents/include/binlog_event.h" #include "m_string.h" #include "map_helpers.h" +#include "my_atomic.h" #include "my_bitmap.h" #include "my_dbug.h" #include "my_inttypes.h" @@ -1183,7 +1184,7 @@ class Relay_log_info : public Rpl_info { the scheduler type. */ ulong mts_wq_no_underrun_cnt; - std::atomic + atomic_counter mts_total_wait_overlap; // Waiting time corresponding to above /* Stats to compute Coordinator waiting time for any Worker available, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5fb773ed7bf..c446b4da858 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4152,7 +4152,7 @@ bool Sys_var_gtid_mode::global_update(THD *thd, set_var *var) { // Update the mode global_var(ulong) = new_gtid_mode; - gtid_mode_counter++; + gtid_mode_counter.fetch_add(1, std::memory_order_release); global_sid_lock->unlock(); lock_count = 3;