diff options
Diffstat (limited to 'storage/innobase/include/sync0policy.h')
-rw-r--r-- | storage/innobase/include/sync0policy.h | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/storage/innobase/include/sync0policy.h b/storage/innobase/include/sync0policy.h new file mode 100644 index 00000000..68397827 --- /dev/null +++ b/storage/innobase/include/sync0policy.h @@ -0,0 +1,296 @@ +/***************************************************************************** + +Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2017, 2018, MariaDB Corporation. + +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 +Foundation; version 2 of the License. + +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 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 Street, Fifth Floor, Boston, MA 02110-1335 USA + +*****************************************************************************/ + +/******************************************************************//** +@file include/sync0policy.h +Policies for mutexes. + +Created 2012-08-21 Sunny Bains. +***********************************************************************/ + +#ifndef sync0policy_h +#define sync0policy_h + +#include "ut0rnd.h" +#include "os0thread.h" +#include "srv0mon.h" +#include "sync0debug.h" + +#ifdef UNIV_DEBUG + +template <typename Mutex> class MutexDebug: public latch_t +{ + /** Mutex to check for lock order violation */ + const Mutex *m_mutex; + /** Filename from where enter was called */ + const char *m_filename; + /** Line mumber in filename */ + unsigned m_line; + /** Thread ID of the thread that owns the mutex */ + os_thread_id_t m_thread_id; + /** Mutex protecting the above members */ + mutable OSMutex m_debug_mutex; + + + void set(const Mutex *mutex, const char *filename, unsigned line, + os_thread_id_t thread_id) + { + m_debug_mutex.enter(); + m_mutex= mutex; + m_filename= filename; + m_line= line; + m_thread_id= thread_id; + m_debug_mutex.exit(); + } + + + const MutexDebug get() const + { + MutexDebug ret; + m_debug_mutex.enter(); + ret.m_mutex= m_mutex; + ret.m_filename= m_filename; + ret.m_line= m_line; + ret.m_thread_id= m_thread_id; + m_debug_mutex.exit(); + return ret; + } + + + /** + Called either when mutex is locked or destroyed. Thus members are protected + from concurrent modification. + */ + void assert_clean_context() + { + ut_ad(!m_mutex); + ut_ad(!m_filename); + ut_ad(!m_line); + ut_ad(m_thread_id == os_thread_id_t(ULINT_UNDEFINED)); + } + + +public: + /** + Called when the mutex is "created". Note: Not from the constructor + but when the mutex is initialised. + @param[in] id Mutex ID + */ + void init(latch_id_t id) + { + ut_ad(id != LATCH_ID_NONE); + m_id= id; + m_debug_mutex.init(); + set(0, 0, 0, os_thread_id_t(ULINT_UNDEFINED)); + } + + + /** Mutex is being destroyed. */ + void destroy() + { + assert_clean_context(); + m_debug_mutex.destroy(); + } + + + /** + Called when an attempt is made to lock the mutex + @param[in] mutex Mutex instance to be locked + @param[in] filename Filename from where it was called + @param[in] line Line number from where it was called + */ + void enter(const Mutex &mutex, const char *filename, unsigned line) + { + MutexDebug context; + ut_ad(!is_owned()); + context.init(m_id); + context.set(&mutex, filename, line, os_thread_get_curr_id()); + /* Check for latch order violation. */ + sync_check_lock_validate(&context); + context.set(0, 0, 0, os_thread_id_t(ULINT_UNDEFINED)); + context.destroy(); + } + + + /** + Called when the mutex is locked + @param[in] mutex Mutex instance that was locked + @param[in] filename Filename from where it was called + @param[in] line Line number from where it was called + */ + void locked(const Mutex &mutex, const char *filename, unsigned line) + { + assert_clean_context(); + set(&mutex, filename, line, os_thread_get_curr_id()); + sync_check_lock_granted(this); + } + + + /** + Called when the mutex is released + @param[in] mutex Mutex that was released + */ + void release(const Mutex &mutex) + { + ut_ad(is_owned()); + set(0, 0, 0, os_thread_id_t(ULINT_UNDEFINED)); + sync_check_unlock(this); + } + + + /** @return true if thread owns the mutex */ + bool is_owned() const + { + return os_thread_eq(get_thread_id(), os_thread_get_curr_id()); + } + + + /** @return the name of the file from the mutex was acquired */ + const char* get_enter_filename() const { return get().m_filename; } + + + /** @return the name of the file from the mutex was acquired */ + unsigned get_enter_line() const { return get().m_line; } + + + /** @return id of the thread that was trying to acquire the mutex */ + os_thread_id_t get_thread_id() const { return get().m_thread_id; } + + + /** + Print information about the latch + @return the string representation + */ + virtual std::string to_string() const + { + std::ostringstream msg; + const MutexDebug ctx= get(); + + msg << m_mutex->policy().to_string(); + if (ctx.m_mutex) + msg << " addr: " << ctx.m_mutex << " acquired: " + << sync_basename(ctx.get_enter_filename()) << ":" + << ctx.get_enter_line(); + else + msg << "Not locked"; + + return(msg.str()); + } +}; +#endif /* UNIV_DEBUG */ + +/** Collect the metrics per mutex instance, no aggregation. */ +template <typename Mutex> +struct GenericPolicy +{ +public: + /** Called when the mutex is "created". Note: Not from the constructor + but when the mutex is initialised. + @param[in] id Mutex ID + @param[in] filename File where mutex was created + @param[in] line Line in filename */ + void init( + const Mutex&, + latch_id_t id, + const char* filename, + uint32_t line) + UNIV_NOTHROW + { + m_id = id; + + latch_meta_t& meta = sync_latch_get_meta(id); + + ut_ad(meta.get_id() == id); + + meta.get_counter()->single_register(&m_count); + + m_filename = filename; + m_line = line; + } + + /** Called when the mutex is destroyed. */ + void destroy() + UNIV_NOTHROW + { + latch_meta_t& meta = sync_latch_get_meta(m_id); + + meta.get_counter()->single_deregister(&m_count); + } + + /** Called after a successful mutex acquire. + @param[in] n_spins Number of times the thread did + spins while trying to acquire the mutex + @param[in] n_waits Number of times the thread waited + in some type of OS queue */ + void add( + uint32_t n_spins, + uint32_t n_waits) + UNIV_NOTHROW + { + /* Currently global on/off. Keeps things simple and fast */ + + if (!m_count.m_enabled) { + + return; + } + + m_count.m_spins += n_spins; + m_count.m_waits += n_waits; + + ++m_count.m_calls; + } + + /** Print the information about the latch + @return the string representation */ + std::string print() const + UNIV_NOTHROW; + + /** @return the latch ID */ + latch_id_t get_id() const + UNIV_NOTHROW + { + return(m_id); + } + + + /** @return the string representation */ + std::string to_string() const + { + return sync_mutex_to_string(get_id(), + std::string(m_filename) + .append(":") + .append(std::to_string(m_line))); + } + +#ifdef UNIV_DEBUG + MutexDebug<Mutex> context; +#endif + +private: + const char *m_filename; + uint32_t m_line; + + /** The user visible counters, registered with the meta-data. */ + latch_meta_t::CounterType::Count m_count; + + /** Latch meta data ID */ + latch_id_t m_id; +}; + +#endif /* sync0policy_h */ |