/**************************************************//**
@file dict/dict0stats_bg.cc
Code used for background table and index stats gathering.
Created Apr 25, 2012 Vasil Dimov
*******************************************************/
#include"dict0dict.h" #include"dict0stats.h" #include"dict0stats_bg.h" #include"row0mysql.h" #include"srv0start.h" #include"fil0fil.h" #include"mysqld.h" #ifdef WITH_WSREP # include "trx0trx.h" # include "mysql/service_wsrep.h" # include "wsrep.h" # include "log.h" #endif
#include <vector>
/** Minimum time interval between stats recalc for a given table */ #define MIN_RECALC_INTERVAL 10/* seconds */ staticvoid dict_stats_schedule(int ms);
/** for signaling recalc::state */ static pthread_cond_t recalc_pool_cond;
/** Work item of the recalc_pool; protected by recalc_pool_mutex */ struct recalc
{ /** identifies a table with persistent statistics */
table_id_t id; /** state of the entry */ enum { IDLE, IN_PROGRESS, IN_PROGRESS_DELETING, DELETING} state;
};
/** The multitude of tables whose stats are to be automatically recalculated */ typedef std::vector<recalc, ut_allocator<recalc>> recalc_pool_t;
/** Pool where we store information on which tables are to be processed
by background statistics gathering. */ static recalc_pool_t recalc_pool; /** Whether the global data structures have been initialized */ staticbool stats_initialised;
static THD *dict_stats_thd;
void reset_thd(MYSQL_THD thd); /*****************************************************************//**
Free the resources occupied by the recalc pool, called once during
thread de-initialization. */ staticvoid dict_stats_recalc_pool_deinit()
{
ut_ad(!srv_read_only_mode);
ut_ad(!recv_sys.rpo);
if (dict_stats_thd)
destroy_background_thd(dict_stats_thd);
}
/*****************************************************************//**
Add a table to the recalc pool, which is processed by the
background stats gathering thread. Only the table id is added to the
list, so the table can be closed after being enqueued and it will be
opened when needed. If the table does not exist later (has been DROPped),
then it will be removed from the pool and skipped. */ staticvoid dict_stats_recalc_pool_add(table_id_t id)
{
ut_ad(!srv_read_only_mode);
ut_ad(!recv_sys.rpo);
ut_ad(id); bool schedule = false;
mysql_mutex_lock(&recalc_pool_mutex);
mysql_mutex_unlock(&recalc_pool_mutex); if (schedule)
dict_stats_schedule_now();
}
/** Update the table modification counter and if necessary, schedulenewestimatesfortableandindexstatisticstobecalculated. @param[in,out]tablepersistentortemporarytable
@param[in,out] thd current session */ void dict_stats_update_if_needed(dict_table_t *table, trx_t &trx) noexcept
{
uint32_t stat{table->stat};
if (UNIV_UNLIKELY(!table->stat_initialized(stat))) { /* The table may have been evicted from dict_sys andreloadedinternallybyInnoDBforFOREIGNKEY processing,butnotreloadedbytheSQLlayer.
/* Calculate new statistics if 1 / 16 of table has been modified sincethelasttimeastatisticsbatchwasrun. Wecalculatestatisticsatmostevery16thround,sincewemayhave
a counter table which is very small and updated very often. */
ulonglong threshold = 16 + n_rows / 16; /* 6.25% */
if (srv_stats_modified_counter) {
threshold = std::min(srv_stats_modified_counter, threshold);
}
if (counter > threshold) { /* this will reset table->stat_modified_counter to 0 */
dict_stats_update_transient(&trx, table);
}
}
/** Delete a table from the auto recalc pool, and ensure that
no statistics are being updated on it. */ void dict_stats_recalc_pool_del(table_id_t id, bool have_mdl_exclusive)
{
ut_ad(!srv_read_only_mode);
ut_ad(!recv_sys.rpo);
ut_ad(id);
mysql_mutex_lock(&recalc_pool_mutex);
auto end= recalc_pool.end(); auto i= std::find_if(recalc_pool.begin(), end,
[&](const recalc &r){return r.id == id;}); if (i != end)
{ switch (i->state) { case recalc::IN_PROGRESS: if (!have_mdl_exclusive)
{
i->state= recalc::IN_PROGRESS_DELETING; do
{
my_cond_wait(&recalc_pool_cond, &recalc_pool_mutex.m_mutex);
end= recalc_pool.end();
i= std::find_if(recalc_pool.begin(), end,
[&](const recalc &r){return r.id == id;}); if (i == end) goto done;
} while (i->state == recalc::IN_PROGRESS_DELETING);
} /* fall through */ case recalc::IDLE:
recalc_pool.erase(i); break; case recalc::IN_PROGRESS_DELETING: case recalc::DELETING: /* another thread will delete the entry in dict_stats_recalc_pool_del() */ break;
}
}
done:
mysql_mutex_unlock(&recalc_pool_mutex);
}
/*****************************************************************//**
Initialize global variables needed for the operation of dict_stats_thread()
Must be called before dict_stats_thread() is started. */ void dict_stats_init()
{
ut_ad(!srv_read_only_mode);
ut_ad(!recv_sys.rpo);
mysql_mutex_init(recalc_pool_mutex_key, &recalc_pool_mutex, nullptr);
pthread_cond_init(&recalc_pool_cond, nullptr);
stats_initialised= true;
}
/*****************************************************************//**
Free resources allocated by dict_stats_init(), must be called
after dict_stats task has exited. */ void dict_stats_deinit()
{ if (!stats_initialised) { return;
}
/* time() could be expensive, the current function iscalledonceeverytimeatablehasbeenchangedmorethan10%and onasystemwithlotsofsmalltables,thiscouldbecomehot.Ifwe findoutthatthisisaproblem,thenthecheckbelowcouldeventually bereplacedwithsomethingelse,thoughatimeintervalisthenatural
approach. */ constbool update_now=
difftime(time(nullptr), table->stats_last_recalc) >= MIN_RECALC_INTERVAL;
/** Check if the recalc pool is empty. */ staticbool is_recalc_pool_empty()
{
mysql_mutex_lock(&recalc_pool_mutex); bool empty= recalc_pool.empty();
mysql_mutex_unlock(&recalc_pool_mutex); return empty;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.