From c82c7328ff1dc13918195508d84f890438cc2a70 Mon Sep 17 00:00:00 2001 From: Yibo Cai Date: Thu, 14 Nov 2019 08:41:31 +0000 Subject: [PATCH] innobase/os_once: optimize os_once with c++11 atomics Replace full barrier with C++11 load-acquire and store-release. --- storage/innobase/dict/dict0dict.cc | 6 +++--- storage/innobase/include/dict0mem.h | 20 ++++++++++---------- storage/innobase/include/os0once.h | 13 ++++++++----- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 0134185..0eee7f0 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -340,13 +340,13 @@ and dict_table_stats_lock()/unlock() become noop on this table. */ void dict_table_stats_latch_create(dict_table_t *table, bool enabled) { if (!enabled) { table->stats_latch = NULL; - table->stats_latch_created = os_once::DONE; + table->stats_latch_created.store(os_once::DONE, order_relaxed); return; } /* We create this lazily the first time it is used. */ table->stats_latch = NULL; - table->stats_latch_created = os_once::NEVER_DONE; + table->stats_latch_created.store(os_once::NEVER_DONE, order_relaxed); } /** Destroy a dict_table_t's stats latch. @@ -354,7 +354,7 @@ This function is only called from either single threaded environment or from a thread that has not shared the table object with other threads. @param[in,out] table table whose stats latch to destroy */ void dict_table_stats_latch_destroy(dict_table_t *table) { - if (table->stats_latch_created == os_once::DONE && + if (table->stats_latch_created.load(order_relaxed) == os_once::DONE && table->stats_latch != NULL) { dict_table_stats_latch_free(table); } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 70fb93a..cf1cea5 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -776,7 +776,7 @@ struct zip_pad_info_t { ulint n_rounds; /*!< number of currently successful rounds */ #ifndef UNIV_HOTBACKUP - volatile os_once::state_t mutex_created; + os_atomic_t mutex_created; /*!< Creation state of mutex member */ #endif /* !UNIV_HOTBACKUP */ }; @@ -1553,7 +1553,7 @@ struct dict_table_t { ib_mutex_t *mutex; /** Creation state of mutex. */ - volatile os_once::state_t mutex_created; + os_atomic_t mutex_created; #endif /* !UNIV_HOTBACKUP */ /** Id of the table. */ @@ -1774,7 +1774,7 @@ struct dict_table_t { /** Statistics for query optimization. @{ */ /** Creation state of 'stats_latch'. */ - volatile os_once::state_t stats_latch_created; + os_atomic_t stats_latch_created; /** This latch protects: "dict_table_t::stat_initialized", @@ -1898,7 +1898,7 @@ detect this and will eventually quit sooner. */ lock_t *autoinc_lock; /** Creation state of autoinc_mutex member */ - volatile os_once::state_t autoinc_mutex_created; + os_atomic_t autoinc_mutex_created; #endif /* !UNIV_HOTBACKUP */ /** Mutex protecting the autoincrement counter. */ @@ -2481,7 +2481,7 @@ or from a thread that has not shared the table object with other threads. @param[in,out] table table whose mutex is to be created */ inline void dict_table_mutex_create_lazy(dict_table_t *table) { table->mutex = nullptr; - table->mutex_created = os_once::NEVER_DONE; + table->mutex_created.store(os_once::NEVER_DONE, order_relaxed); } /** Destroy the mutex of a given table. @@ -2489,7 +2489,7 @@ This function is only called from either single threaded environment or from a thread that has not shared the table object with other threads. @param[in,out] table table whose mutex is to be created */ inline void dict_table_mutex_destroy(dict_table_t *table) { - if (table->mutex_created == os_once::DONE) { + if (table->mutex_created.load(order_relaxed) == os_once::DONE) { if (table->mutex != nullptr) { mutex_free(table->mutex); UT_DELETE(table->mutex); @@ -2502,7 +2502,7 @@ This function is only called from either single threaded environment or from a thread that has not shared the table object with other threads. @param[in,out] table table whose stats latch to destroy */ inline void dict_table_autoinc_destroy(dict_table_t *table) { - if (table->autoinc_mutex_created == os_once::DONE) { + if (table->autoinc_mutex_created.load(order_relaxed) == os_once::DONE) { if (table->autoinc_mutex != NULL) { mutex_free(table->autoinc_mutex); UT_DELETE(table->autoinc_mutex); @@ -2522,7 +2522,7 @@ or from a thread that has not shared the table object with other threads. inline void dict_table_autoinc_create_lazy(dict_table_t *table) { table->autoinc_mutex = NULL; table->autoinc_persisted_mutex = NULL; - table->autoinc_mutex_created = os_once::NEVER_DONE; + table->autoinc_mutex_created.store(os_once::NEVER_DONE, order_relaxed); } /** Request a lazy creation of dict_index_t::zip_pad::mutex. @@ -2531,7 +2531,7 @@ or from a thread that has not shared the table object with other threads. @param[in,out] index index whose zip_pad mutex is to be created */ inline void dict_index_zip_pad_mutex_create_lazy(dict_index_t *index) { index->zip_pad.mutex = NULL; - index->zip_pad.mutex_created = os_once::NEVER_DONE; + index->zip_pad.mutex_created.store(os_once::NEVER_DONE, order_relaxed); } /** Destroy the zip_pad_mutex of the given index. @@ -2539,7 +2539,7 @@ This function is only called from either single threaded environment or from a thread that has not shared the table object with other threads. @param[in,out] index index whose stats latch to destroy */ inline void dict_index_zip_pad_mutex_destroy(dict_index_t *index) { - if (index->zip_pad.mutex_created == os_once::DONE && + if (index->zip_pad.mutex_created.load(order_relaxed) == os_once::DONE && index->zip_pad.mutex != NULL) { mutex_free(index->zip_pad.mutex); UT_DELETE(index->zip_pad.mutex); diff --git a/storage/innobase/include/os0once.h b/storage/innobase/include/os0once.h index 043f934..d7320a1 100644 --- a/storage/innobase/include/os0once.h +++ b/storage/innobase/include/os0once.h @@ -79,20 +79,23 @@ class os_once { @param[in,out] state control variable @param[in] do_func function to call @param[in,out] do_func_arg an argument to pass to do_func(). */ - static void do_or_wait_for_done(volatile state_t *state, + static void do_or_wait_for_done(os_atomic_t *state, void (*do_func)(void *), void *do_func_arg) { /* Avoid calling os_compare_and_swap_uint32() in the most common case. */ - if (*state == DONE) { + if (state->load(order_relaxed) == DONE) { return; } - if (os_compare_and_swap_uint32(state, NEVER_DONE, IN_PROGRESS)) { + state_t expected = NEVER_DONE; + if (state->compare_exchange_strong(expected, IN_PROGRESS, order_acquire)) { /* We are the first. Call the function. */ do_func(do_func_arg); - const bool swapped = os_compare_and_swap_uint32(state, IN_PROGRESS, DONE); + expected = IN_PROGRESS; + const bool swapped = state->compare_exchange_strong(expected, DONE, + order_release); ut_a(swapped); } else { @@ -101,7 +104,7 @@ class os_once { now or DONE (it has already been called and completed). Wait for it to become DONE. */ for (;;) { - const state_t s = *state; + const state_t s = state->load(order_relaxed); switch (s) { case DONE: -- 2.7.4