mirror of
https://github.com/MariaDB/server.git
synced 2026-01-06 05:22:24 +03:00
MDEV-10296 - Multi-instance table cache
Table cache instances autosizing.
This commit is contained in:
@@ -1092,7 +1092,7 @@ The following options may be given as the first argument:
|
||||
--table-open-cache=#
|
||||
The number of cached open tables
|
||||
--table-open-cache-instances=#
|
||||
The number of table cache instances
|
||||
Maximum number of table cache instances
|
||||
--tc-heuristic-recover=name
|
||||
Decision to use in heuristic recover process. One of: OFF,
|
||||
COMMIT, ROLLBACK
|
||||
@@ -1459,7 +1459,7 @@ sysdate-is-now FALSE
|
||||
table-cache 431
|
||||
table-definition-cache 400
|
||||
table-open-cache 431
|
||||
table-open-cache-instances 1
|
||||
table-open-cache-instances 8
|
||||
tc-heuristic-recover OFF
|
||||
thread-cache-size 151
|
||||
thread-pool-idle-timeout 60
|
||||
|
||||
@@ -3889,12 +3889,12 @@ READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME TABLE_OPEN_CACHE_INSTANCES
|
||||
SESSION_VALUE NULL
|
||||
GLOBAL_VALUE 1
|
||||
GLOBAL_VALUE 8
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE 1
|
||||
DEFAULT_VALUE 8
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
VARIABLE_COMMENT The number of table cache instances
|
||||
VARIABLE_COMMENT Maximum number of table cache instances
|
||||
NUMERIC_MIN_VALUE 1
|
||||
NUMERIC_MAX_VALUE 64
|
||||
NUMERIC_BLOCK_SIZE 1
|
||||
|
||||
@@ -4659,12 +4659,12 @@ READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME TABLE_OPEN_CACHE_INSTANCES
|
||||
SESSION_VALUE NULL
|
||||
GLOBAL_VALUE 1
|
||||
GLOBAL_VALUE 8
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE 1
|
||||
DEFAULT_VALUE 8
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
VARIABLE_COMMENT The number of table cache instances
|
||||
VARIABLE_COMMENT Maximum number of table cache instances
|
||||
NUMERIC_MIN_VALUE 1
|
||||
NUMERIC_MAX_VALUE 64
|
||||
NUMERIC_BLOCK_SIZE 1
|
||||
|
||||
@@ -3228,9 +3228,9 @@ static Sys_var_ulong Sys_table_cache_size(
|
||||
ON_UPDATE(fix_table_open_cache));
|
||||
|
||||
static Sys_var_ulong Sys_table_cache_instances(
|
||||
"table_open_cache_instances", "The number of table cache instances",
|
||||
"table_open_cache_instances", "Maximum number of table cache instances",
|
||||
READ_ONLY GLOBAL_VAR(tc_instances), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(1, 64), DEFAULT(1), BLOCK_SIZE(1));
|
||||
VALID_RANGE(1, 64), DEFAULT(8), BLOCK_SIZE(1));
|
||||
|
||||
static Sys_var_ulong Sys_thread_cache_size(
|
||||
"thread_cache_size",
|
||||
|
||||
@@ -1027,6 +1027,7 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
uint32 instance; /** Table cache instance this TABLE is belonging to */
|
||||
THD *in_use; /* Which thread uses this */
|
||||
Field **field; /* Pointer to fields */
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@
|
||||
ulong tdc_size; /**< Table definition cache threshold for LRU eviction. */
|
||||
ulong tc_size; /**< Table cache threshold for LRU eviction. */
|
||||
ulong tc_instances;
|
||||
static uint32 tc_active_instances= 1;
|
||||
static uint32 tc_contention_warning_reported;
|
||||
|
||||
/** Data collections. */
|
||||
static LF_HASH tdc_hash; /**< Collection of TABLE_SHARE objects. */
|
||||
@@ -127,10 +129,12 @@ struct Table_cache_instance
|
||||
I_P_List_null_counter, I_P_List_fast_push_back<TABLE> >
|
||||
free_tables;
|
||||
ulong records;
|
||||
uint mutex_waits;
|
||||
uint mutex_nowaits;
|
||||
/** Avoid false sharing between instances */
|
||||
char pad[CPU_LEVEL1_DCACHE_LINESIZE];
|
||||
|
||||
Table_cache_instance(): records(0)
|
||||
Table_cache_instance(): records(0), mutex_waits(0), mutex_nowaits(0)
|
||||
{
|
||||
mysql_mutex_init(key_LOCK_table_cache, &LOCK_table_cache,
|
||||
MY_MUTEX_INIT_FAST);
|
||||
@@ -142,6 +146,68 @@ struct Table_cache_instance
|
||||
DBUG_ASSERT(free_tables.is_empty());
|
||||
DBUG_ASSERT(records == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
Lock table cache mutex and check contention.
|
||||
|
||||
Instance is considered contested if more than 20% of mutex acquisiotions
|
||||
can't be served immediately. Up to 100 000 probes may be performed to avoid
|
||||
instance activation on short sporadic peaks. 100 000 is estimated maximum
|
||||
number of queries one instance can serve in one second.
|
||||
|
||||
These numbers work well on a 2 socket / 20 core / 40 threads Intel Broadwell
|
||||
system, that is expected number of instances is activated within reasonable
|
||||
warmup time. It may have to be adjusted for other systems.
|
||||
|
||||
Only TABLE object acquistion is instrumented. We intentionally avoid this
|
||||
overhead on TABLE object release. All other table cache mutex acquistions
|
||||
are considered out of hot path and are not instrumented either.
|
||||
*/
|
||||
void lock_and_check_contention(uint32 n_instances, uint32 instance)
|
||||
{
|
||||
if (mysql_mutex_trylock(&LOCK_table_cache))
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_table_cache);
|
||||
if (++mutex_waits == 20000)
|
||||
{
|
||||
if (n_instances < tc_instances)
|
||||
{
|
||||
if (my_atomic_cas32_weak_explicit(&tc_active_instances, &n_instances,
|
||||
n_instances + 1,
|
||||
MY_MEMORY_ORDER_RELAXED,
|
||||
MY_MEMORY_ORDER_RELAXED))
|
||||
{
|
||||
sql_print_information("Detected table cache mutex contention at instance %d: "
|
||||
"%d%% waits. Additional table cache instance "
|
||||
"activated. Number of instances after "
|
||||
"activation: %d.",
|
||||
instance + 1,
|
||||
mutex_waits * 100 / (mutex_nowaits + mutex_waits),
|
||||
n_instances + 1);
|
||||
}
|
||||
}
|
||||
else if (!my_atomic_fas32_explicit(&tc_contention_warning_reported, 1,
|
||||
MY_MEMORY_ORDER_RELAXED))
|
||||
{
|
||||
sql_print_warning("Detected table cache mutex contention at instance %d: "
|
||||
"%d%% waits. Additional table cache instance "
|
||||
"cannot be activated: consider raising "
|
||||
"table_open_cache_instances. Number of active "
|
||||
"instances: %d.",
|
||||
instance + 1,
|
||||
mutex_waits * 100 / (mutex_nowaits + mutex_waits),
|
||||
n_instances);
|
||||
}
|
||||
mutex_waits= 0;
|
||||
mutex_nowaits= 0;
|
||||
}
|
||||
}
|
||||
else if (++mutex_nowaits == 80000)
|
||||
{
|
||||
mutex_waits= 0;
|
||||
mutex_nowaits= 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -287,11 +353,12 @@ void tc_purge(bool mark_flushed)
|
||||
|
||||
void tc_add_table(THD *thd, TABLE *table)
|
||||
{
|
||||
ulong i= thd->thread_id % tc_instances;
|
||||
uint32 i= thd->thread_id % my_atomic_load32_explicit(&tc_active_instances, MY_MEMORY_ORDER_RELAXED);
|
||||
TABLE *LRU_table= 0;
|
||||
TDC_element *element= table->s->tdc;
|
||||
|
||||
DBUG_ASSERT(table->in_use == thd);
|
||||
table->instance= i;
|
||||
mysql_mutex_lock(&element->LOCK_table_share);
|
||||
/* Wait for MDL deadlock detector to complete traversing tdc.all_tables. */
|
||||
while (element->all_tables_refs)
|
||||
@@ -327,10 +394,12 @@ void tc_add_table(THD *thd, TABLE *table)
|
||||
|
||||
static TABLE *tc_acquire_table(THD *thd, TDC_element *element)
|
||||
{
|
||||
ulong i= thd->thread_id % tc_instances;
|
||||
uint32 n_instances=
|
||||
my_atomic_load32_explicit(&tc_active_instances, MY_MEMORY_ORDER_RELAXED);
|
||||
uint32 i= thd->thread_id % n_instances;
|
||||
TABLE *table;
|
||||
|
||||
mysql_mutex_lock(&tc[i].LOCK_table_cache);
|
||||
tc[i].lock_and_check_contention(n_instances, i);
|
||||
table= element->free_tables[i].list.pop_front();
|
||||
if (table)
|
||||
{
|
||||
@@ -375,7 +444,7 @@ static TABLE *tc_acquire_table(THD *thd, TDC_element *element)
|
||||
|
||||
void tc_release_table(TABLE *table)
|
||||
{
|
||||
ulong i= table->in_use->thread_id % tc_instances;
|
||||
uint32 i= table->instance;
|
||||
DBUG_ASSERT(table->in_use);
|
||||
DBUG_ASSERT(table->file);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user