mariadb/storage/innobase/include/sync0policy.h
2022-01-29 15:41:05 +01:00

296 lines
7.3 KiB
C++

/*****************************************************************************
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 */