MDEV-4702 - Reduce usage of LOCK_open
Following variables do not require LOCK_open protection anymore: - table_def_cache (renamed to tdc_hash) is protected by rw-lock LOCK_tdc_hash; - table_def_shutdown_in_progress doesn't need LOCK_open protection; - last_table_id use atomics; - TABLE_SHARE::ref_count (renamed to TABLE_SHARE::tdc.ref_count) is protected by TABLE_SHARE::tdc.LOCK_table_share; - TABLE_SHARE::next, ::prev (renamed to tdc.next and tdc.prev), oldest_unused_share, end_of_unused_share are protected by LOCK_unused_shares; - TABLE_SHARE::m_flush_tickets (renamed to tdc.m_flush_tickets) is protected by TABLE_SHARE::tdc.LOCK_table_share; - refresh_version (renamed to tdc_version) use atomics.
This commit is contained in:
parent
b882a3e83e
commit
b7f9c89423
@ -102,6 +102,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
||||
../sql/my_apc.cc ../sql/my_apc.h
|
||||
../sql/rpl_gtid.cc
|
||||
../sql/compat56.cc
|
||||
../sql/table_cache.cc
|
||||
${GEN_SOURCES}
|
||||
${MYSYS_LIBWRAP_SOURCE}
|
||||
)
|
||||
|
@ -927,6 +927,9 @@ The following options may be given as the first argument:
|
||||
The number of cached table definitions
|
||||
--table-open-cache=#
|
||||
The number of cached open tables
|
||||
--table-open-cache-instances=#
|
||||
MySQL 5.6 compatible option. Not used or needed in
|
||||
MariaDB
|
||||
--tc-heuristic-recover=name
|
||||
Decision to use in heuristic recover process. Possible
|
||||
values are COMMIT or ROLLBACK.
|
||||
@ -1258,6 +1261,7 @@ sysdate-is-now FALSE
|
||||
table-cache 400
|
||||
table-definition-cache 400
|
||||
table-open-cache 400
|
||||
table-open-cache-instances 1
|
||||
tc-heuristic-recover COMMIT
|
||||
thread-cache-size 0
|
||||
thread-pool-idle-timeout 60
|
||||
|
@ -20,15 +20,15 @@ where name like 'Wait/Synch/Rwlock/sql/%'
|
||||
order by name limit 10;
|
||||
NAME ENABLED TIMED
|
||||
wait/synch/rwlock/sql/LOCK_dboptions YES YES
|
||||
wait/synch/rwlock/sql/LOCK_flush YES YES
|
||||
wait/synch/rwlock/sql/LOCK_grant YES YES
|
||||
wait/synch/rwlock/sql/LOCK_system_variables_hash YES YES
|
||||
wait/synch/rwlock/sql/LOCK_sys_init_connect YES YES
|
||||
wait/synch/rwlock/sql/LOCK_sys_init_slave YES YES
|
||||
wait/synch/rwlock/sql/LOCK_tdc YES YES
|
||||
wait/synch/rwlock/sql/LOGGER::LOCK_logger YES YES
|
||||
wait/synch/rwlock/sql/MDL_context::LOCK_waiting_for YES YES
|
||||
wait/synch/rwlock/sql/MDL_lock::rwlock YES YES
|
||||
wait/synch/rwlock/sql/Query_cache_query::lock YES YES
|
||||
wait/synch/rwlock/sql/THR_LOCK_servers YES YES
|
||||
select * from performance_schema.setup_instruments
|
||||
where name like 'Wait/Synch/Cond/sql/%'
|
||||
and name not in (
|
||||
|
@ -0,0 +1,3 @@
|
||||
select @@table_open_cache_instances;
|
||||
@@table_open_cache_instances
|
||||
1
|
@ -0,0 +1 @@
|
||||
select @@table_open_cache_instances;
|
@ -91,6 +91,7 @@ SET (SQL_SOURCE
|
||||
../sql-common/mysql_async.c
|
||||
my_apc.cc my_apc.h
|
||||
rpl_gtid.cc
|
||||
table_cache.cc
|
||||
${GEN_SOURCES}
|
||||
${MYSYS_LIBWRAP_SOURCE}
|
||||
)
|
||||
|
@ -376,9 +376,7 @@ ndbcluster_binlog_open_table(THD *thd, NDB_SHARE *share,
|
||||
free_table_share(table_share);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
assign_new_table_id(table_share);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
tdc_assign_new_table_id(table_share);
|
||||
|
||||
if (!reopen)
|
||||
{
|
||||
|
@ -4718,7 +4718,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin,
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
DBUG_ASSERT(share->error); // get_cached_table_share needs that
|
||||
DBUG_ASSERT(share->error); // tdc_lock_share needs that
|
||||
/*
|
||||
report an error, unless it is "generic" and a more
|
||||
specific one was already reported
|
||||
@ -4856,29 +4856,27 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
||||
|
||||
Table_exists_error_handler no_such_table_handler;
|
||||
thd->push_internal_handler(&no_such_table_handler);
|
||||
TABLE_SHARE *share= get_table_share(thd, db, table_name, flags);
|
||||
TABLE_SHARE *share= tdc_acquire_share(thd, db, table_name, flags);
|
||||
thd->pop_internal_handler();
|
||||
|
||||
if (hton && share)
|
||||
{
|
||||
*hton= share->db_type();
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
release_table_share(share);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
tdc_release_share(share);
|
||||
}
|
||||
|
||||
// the table doesn't exist if we've caught ER_NO_SUCH_TABLE and nothing else
|
||||
DBUG_RETURN(!no_such_table_handler.safely_trapped_errors());
|
||||
}
|
||||
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
TABLE_SHARE *share= get_cached_table_share(db, table_name);
|
||||
if (hton && share)
|
||||
*hton= share->db_type();
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
|
||||
TABLE_SHARE *share= tdc_lock_share(db, table_name);
|
||||
if (share)
|
||||
{
|
||||
if (hton)
|
||||
*hton= share->db_type();
|
||||
tdc_unlock_share(share);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
char path[FN_REFLEN + 1];
|
||||
size_t path_len = build_table_filename(path, sizeof(path) - 1,
|
||||
|
@ -40,9 +40,7 @@
|
||||
#include "hostname.h" // hostname_cache_free, hostname_cache_init
|
||||
#include "sql_acl.h" // acl_free, grant_free, acl_init,
|
||||
// grant_init
|
||||
#include "sql_base.h" // table_def_free, table_def_init,
|
||||
// cached_open_tables,
|
||||
// cached_table_definitions
|
||||
#include "sql_base.h"
|
||||
#include "sql_test.h" // mysql_print_status
|
||||
#include "item_create.h" // item_create_cleanup, item_create_init
|
||||
#include "sql_servers.h" // servers_free, servers_init
|
||||
@ -473,7 +471,6 @@ int32 thread_count;
|
||||
int32 thread_running;
|
||||
ulong thread_created;
|
||||
ulong back_log, connect_timeout, concurrency, server_id;
|
||||
ulong table_cache_size, table_def_size;
|
||||
ulong what_to_log;
|
||||
ulong slow_launch_time, slave_open_temp_tables;
|
||||
ulong open_files_limit, max_binlog_size;
|
||||
@ -489,7 +486,6 @@ ulonglong binlog_stmt_cache_size=0;
|
||||
ulonglong max_binlog_stmt_cache_size=0;
|
||||
ulonglong query_cache_size=0;
|
||||
ulong query_cache_limit=0;
|
||||
ulong refresh_version; /* Increments on each reload */
|
||||
ulong executed_events=0;
|
||||
query_id_t global_query_id;
|
||||
my_atomic_rwlock_t global_query_id_lock;
|
||||
@ -843,7 +839,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
|
||||
key_LOCK_manager,
|
||||
key_LOCK_prepared_stmt_count,
|
||||
key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
|
||||
key_LOCK_system_variables_hash, key_LOCK_table_share, key_LOCK_thd_data,
|
||||
key_LOCK_system_variables_hash, key_LOCK_thd_data,
|
||||
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
|
||||
key_master_info_data_lock, key_master_info_run_lock,
|
||||
key_master_info_sleep_lock,
|
||||
@ -902,7 +898,6 @@ static PSI_mutex_info all_server_mutexes[]=
|
||||
{ &key_LOCK_server_started, "LOCK_server_started", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_status, "LOCK_status", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_system_variables_hash, "LOCK_system_variables_hash", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_table_share, "LOCK_table_share", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_stats, "LOCK_stats", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_global_user_client_stats, "LOCK_global_user_client_stats", PSI_FLAG_GLOBAL},
|
||||
{ &key_LOCK_global_table_stats, "LOCK_global_table_stats", PSI_FLAG_GLOBAL},
|
||||
@ -1963,14 +1958,14 @@ void clean_up(bool print_message)
|
||||
udf_free();
|
||||
#endif
|
||||
}
|
||||
table_def_start_shutdown();
|
||||
tdc_start_shutdown();
|
||||
plugin_shutdown();
|
||||
ha_end();
|
||||
if (tc_log)
|
||||
tc_log->close();
|
||||
delegates_destroy();
|
||||
xid_cache_free();
|
||||
table_def_free();
|
||||
tdc_deinit();
|
||||
mdl_destroy();
|
||||
key_caches.delete_elements((void (*)(const char*, uchar*)) free_key_cache);
|
||||
wt_end();
|
||||
@ -4012,7 +4007,7 @@ static int init_common_variables()
|
||||
|
||||
/* MyISAM requires two file handles per table. */
|
||||
wanted_files= (10 + max_connections + extra_max_connections +
|
||||
table_cache_size*2);
|
||||
tc_size * 2);
|
||||
/*
|
||||
We are trying to allocate no less than max_connections*5 file
|
||||
handles (i.e. we are trying to set the limit so that they will
|
||||
@ -4039,20 +4034,19 @@ static int init_common_variables()
|
||||
max_connections= (ulong) MY_MIN(files-10-TABLE_OPEN_CACHE_MIN*2,
|
||||
max_connections);
|
||||
/*
|
||||
Decrease table_cache_size according to max_connections, but
|
||||
Decrease tc_size according to max_connections, but
|
||||
not below TABLE_OPEN_CACHE_MIN. Outer MY_MIN() ensures that we
|
||||
never increase table_cache_size automatically (that could
|
||||
never increase tc_size automatically (that could
|
||||
happen if max_connections is decreased above).
|
||||
*/
|
||||
table_cache_size= (ulong) MY_MIN(MY_MAX((files-10-max_connections)/2,
|
||||
TABLE_OPEN_CACHE_MIN),
|
||||
table_cache_size);
|
||||
tc_size= (ulong) MY_MIN(MY_MAX((files - 10 - max_connections) / 2,
|
||||
TABLE_OPEN_CACHE_MIN), tc_size);
|
||||
DBUG_PRINT("warning",
|
||||
("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld",
|
||||
files, max_connections, table_cache_size));
|
||||
files, max_connections, tc_size));
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_warning("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld",
|
||||
files, max_connections, table_cache_size);
|
||||
files, max_connections, tc_size);
|
||||
}
|
||||
else if (global_system_variables.log_warnings)
|
||||
sql_print_warning("Could not increase number of max_open_files to more than %u (request: %u)", files, wanted_files);
|
||||
@ -4477,7 +4471,7 @@ static int init_server_components()
|
||||
all things are initialized so that unireg_abort() doesn't fail
|
||||
*/
|
||||
mdl_init();
|
||||
if (table_def_init() | hostname_cache_init())
|
||||
if (tdc_init() | hostname_cache_init())
|
||||
unireg_abort(1);
|
||||
|
||||
query_cache_set_min_res_unit(query_cache_min_res_unit);
|
||||
@ -5054,8 +5048,8 @@ int mysqld_main(int argc, char **argv)
|
||||
if (pfs_param.m_enabled && !opt_help && !opt_bootstrap)
|
||||
{
|
||||
/* Add sizing hints from the server sizing parameters. */
|
||||
pfs_param.m_hints.m_table_definition_cache= table_def_size;
|
||||
pfs_param.m_hints.m_table_open_cache= table_cache_size;
|
||||
pfs_param.m_hints.m_table_definition_cache= tdc_size;
|
||||
pfs_param.m_hints.m_table_open_cache= tc_size;
|
||||
pfs_param.m_hints.m_max_connections= max_connections;
|
||||
pfs_param.m_hints.m_open_files_limit= open_files_limit;
|
||||
PSI_hook= initialize_performance_schema(&pfs_param);
|
||||
@ -5286,12 +5280,6 @@ int mysqld_main(int argc, char **argv)
|
||||
|
||||
execute_ddl_log_recovery();
|
||||
|
||||
/*
|
||||
We must have LOCK_open before LOCK_global_system_variables because
|
||||
LOCK_open is held while sql_plugin.c::intern_sys_var_ptr() is called.
|
||||
*/
|
||||
mysql_mutex_record_order(&LOCK_open, &LOCK_global_system_variables);
|
||||
|
||||
if (Events::init(opt_noacl || opt_bootstrap))
|
||||
unireg_abort(1);
|
||||
|
||||
@ -6944,7 +6932,7 @@ struct my_option my_long_options[]=
|
||||
0, 0, 0,
|
||||
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"table_cache", 0, "Deprecated; use --table-open-cache instead.",
|
||||
&table_cache_size, &table_cache_size, 0, GET_ULONG,
|
||||
&tc_size, &tc_size, 0, GET_ULONG,
|
||||
REQUIRED_ARG, TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0}
|
||||
};
|
||||
|
||||
@ -7080,7 +7068,7 @@ static int show_open_tables(THD *thd, SHOW_VAR *var, char *buff)
|
||||
{
|
||||
var->type= SHOW_LONG;
|
||||
var->value= buff;
|
||||
*((long *)buff)= (long)cached_open_tables();
|
||||
*((long *) buff)= (long) tc_records();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -7098,10 +7086,20 @@ static int show_table_definitions(THD *thd, SHOW_VAR *var, char *buff)
|
||||
{
|
||||
var->type= SHOW_LONG;
|
||||
var->value= buff;
|
||||
*((long *)buff)= (long)cached_table_definitions();
|
||||
*((long *) buff)= (long) tdc_records();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int show_flush_commands(THD *thd, SHOW_VAR *var, char *buff)
|
||||
{
|
||||
var->type= SHOW_LONG;
|
||||
var->value= buff;
|
||||
*((long *) buff)= (long) tdc_refresh_version();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
|
||||
/* Functions relying on CTX */
|
||||
static int show_ssl_ctx_sess_accept(THD *thd, SHOW_VAR *var, char *buff)
|
||||
@ -7557,7 +7555,7 @@ SHOW_VAR status_vars[]= {
|
||||
{"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS},
|
||||
{"Feature_trigger", (char*) offsetof(STATUS_VAR, feature_trigger), SHOW_LONG_STATUS},
|
||||
{"Feature_xml", (char*) offsetof(STATUS_VAR, feature_xml), SHOW_LONG_STATUS},
|
||||
{"Flush_commands", (char*) &refresh_version, SHOW_LONG_NOFLUSH},
|
||||
{"Flush_commands", (char*) &show_flush_commands, SHOW_SIMPLE_FUNC},
|
||||
{"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count), SHOW_LONG_STATUS},
|
||||
{"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count), SHOW_LONG_STATUS},
|
||||
{"Handler_discover", (char*) offsetof(STATUS_VAR, ha_discover_count), SHOW_LONG_STATUS},
|
||||
@ -7890,7 +7888,6 @@ static int mysql_init_variables(void)
|
||||
log_error_file_ptr= log_error_file;
|
||||
protocol_version= PROTOCOL_VERSION;
|
||||
what_to_log= ~ (1L << (uint) COM_TIME);
|
||||
refresh_version= 1L; /* Increments on each reload */
|
||||
denied_connections= 0;
|
||||
executed_events= 0;
|
||||
global_query_id= thread_id= 1L;
|
||||
|
@ -160,7 +160,6 @@ extern ulonglong query_cache_size;
|
||||
extern ulong query_cache_limit;
|
||||
extern ulong query_cache_min_res_unit;
|
||||
extern ulong slow_launch_threads, slow_launch_time;
|
||||
extern ulong table_cache_size, table_def_size;
|
||||
extern MYSQL_PLUGIN_IMPORT ulong max_connections;
|
||||
extern ulong max_connect_errors, connect_timeout;
|
||||
extern my_bool slave_allow_batching;
|
||||
@ -248,7 +247,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
|
||||
key_LOCK_logger, key_LOCK_manager,
|
||||
key_LOCK_prepared_stmt_count,
|
||||
key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
|
||||
key_LOCK_table_share, key_LOCK_thd_data,
|
||||
key_LOCK_thd_data,
|
||||
key_LOCK_user_conn, key_LOG_LOCK_log,
|
||||
key_master_info_data_lock, key_master_info_run_lock,
|
||||
key_master_info_sleep_lock,
|
||||
|
@ -131,15 +131,13 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
DBUG_RETURN(0);
|
||||
has_mdl_lock= TRUE;
|
||||
|
||||
share= get_table_share_shortlived(thd, table_list, GTS_TABLE);
|
||||
share= tdc_acquire_share_shortlived(thd, table_list, GTS_TABLE);
|
||||
if (share == NULL)
|
||||
DBUG_RETURN(0); // Can't open frm file
|
||||
|
||||
if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
release_table_share(share);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
tdc_release_share(share);
|
||||
DBUG_RETURN(0); // Out of memory
|
||||
}
|
||||
table= &tmp_table;
|
||||
@ -262,11 +260,7 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
|
||||
end:
|
||||
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
|
||||
if (table == &tmp_table)
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
closefrm(table, 1); // Free allocated memory
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
}
|
||||
/* In case of a temporary table there will be no metadata lock. */
|
||||
if (error && has_mdl_lock)
|
||||
thd->mdl_context.release_transactional_locks();
|
||||
|
1058
sql/sql_base.cc
1058
sql/sql_base.cc
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@
|
||||
#include "sql_trigger.h" /* trg_event_type */
|
||||
#include "sql_class.h" /* enum_mark_columns */
|
||||
#include "mysqld.h" /* key_map */
|
||||
#include "table_cache.h"
|
||||
|
||||
class Item_ident;
|
||||
struct Name_resolution_context;
|
||||
@ -59,93 +60,9 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
|
||||
IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE,
|
||||
IGNORE_EXCEPT_NON_UNIQUE};
|
||||
|
||||
enum enum_tdc_remove_table_type {TDC_RT_REMOVE_ALL, TDC_RT_REMOVE_NOT_OWN,
|
||||
TDC_RT_REMOVE_UNUSED,
|
||||
TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE};
|
||||
|
||||
/* bits for last argument to remove_table_from_cache() */
|
||||
#define RTFC_NO_FLAG 0x0000
|
||||
#define RTFC_OWNED_BY_THD_FLAG 0x0001
|
||||
#define RTFC_WAIT_OTHER_THREAD_FLAG 0x0002
|
||||
#define RTFC_CHECK_KILLED_FLAG 0x0004
|
||||
|
||||
extern HASH table_def_cache;
|
||||
|
||||
bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
|
||||
extern mysql_mutex_t LOCK_open;
|
||||
bool table_cache_init(void);
|
||||
void table_cache_free(void);
|
||||
bool table_def_init(void);
|
||||
void table_def_free(void);
|
||||
void table_def_start_shutdown(void);
|
||||
void assign_new_table_id(TABLE_SHARE *share);
|
||||
uint cached_table_definitions(void);
|
||||
uint cached_open_tables(void);
|
||||
|
||||
/**
|
||||
Create a table cache key for non-temporary table.
|
||||
|
||||
@param key Buffer for key (must be at least MAX_DBKEY_LENGTH bytes).
|
||||
@param db Database name.
|
||||
@param table_name Table name.
|
||||
|
||||
@return Length of key.
|
||||
|
||||
@sa create_table_def_key(thd, char *, table_list, bool)
|
||||
*/
|
||||
|
||||
inline uint
|
||||
create_table_def_key(char *key, const char *db, const char *table_name)
|
||||
{
|
||||
/*
|
||||
In theory caller should ensure that both db and table_name are
|
||||
not longer than NAME_LEN bytes. In practice we play safe to avoid
|
||||
buffer overruns.
|
||||
*/
|
||||
return (uint)(strmake(strmake(key, db, NAME_LEN) + 1, table_name,
|
||||
NAME_LEN) - key + 1);
|
||||
}
|
||||
|
||||
uint create_tmp_table_def_key(THD *thd, char *key, const char *db,
|
||||
const char *table_name);
|
||||
uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
|
||||
TABLE_SHARE *get_table_share(THD *thd, const char *db, const char *table_name,
|
||||
const char *key, uint key_length, uint flags,
|
||||
my_hash_value_type hash_value);
|
||||
void release_table_share(TABLE_SHARE *share);
|
||||
TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
|
||||
|
||||
// convenience helper: call get_table_share() without precomputed hash_value
|
||||
static inline TABLE_SHARE *get_table_share(THD *thd, const char *db,
|
||||
const char *table_name,
|
||||
const char *key, uint key_length,
|
||||
uint flags)
|
||||
{
|
||||
return get_table_share(thd, db, table_name, key, key_length, flags,
|
||||
my_calc_hash(&table_def_cache, (uchar*) key, key_length));
|
||||
}
|
||||
|
||||
// convenience helper: call get_table_share() without precomputed cache key
|
||||
static inline TABLE_SHARE *get_table_share(THD *thd, const char *db,
|
||||
const char *table_name, uint flags)
|
||||
{
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
uint key_length;
|
||||
key_length= create_table_def_key(key, db, table_name);
|
||||
return get_table_share(thd, db, table_name, key, key_length, flags);
|
||||
}
|
||||
|
||||
// convenience helper: call get_table_share() reusing the MDL cache key.
|
||||
// NOTE: lifetime of the returned TABLE_SHARE is limited by the
|
||||
// lifetime of the TABLE_LIST object!!!
|
||||
static inline TABLE_SHARE *get_table_share_shortlived(THD *thd, TABLE_LIST *tl,
|
||||
uint flags)
|
||||
{
|
||||
const char *key;
|
||||
uint key_length= get_table_def_key(tl, &key);
|
||||
return get_table_share(thd, tl->db, tl->table_name, key, key_length, flags);
|
||||
}
|
||||
|
||||
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
|
||||
uint lock_flags);
|
||||
|
||||
@ -326,6 +243,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
|
||||
int decide_logging_format(THD *thd, TABLE_LIST *tables);
|
||||
void free_io_cache(TABLE *entry);
|
||||
void intern_close_table(TABLE *entry);
|
||||
void kill_delayed_threads_for_table(TABLE_SHARE *share);
|
||||
void close_thread_table(THD *thd, TABLE **table_ptr);
|
||||
bool close_temporary_tables(THD *thd);
|
||||
TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
|
||||
@ -361,9 +279,6 @@ void close_all_tables_for_name(THD *thd, TABLE_SHARE *share,
|
||||
ha_extra_function extra,
|
||||
TABLE *skip_table);
|
||||
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild);
|
||||
void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
||||
const char *db, const char *table_name,
|
||||
bool has_lock);
|
||||
bool tdc_open_view(THD *thd, TABLE_LIST *table_list, const char *alias,
|
||||
const char *cache_key, uint cache_key_length,
|
||||
MEM_ROOT *mem_root, uint flags);
|
||||
@ -377,7 +292,6 @@ static inline bool tdc_open_view(THD *thd, TABLE_LIST *table_list,
|
||||
return tdc_open_view(thd, table_list, alias, key, key_length, mem_root, flags);
|
||||
}
|
||||
|
||||
void tdc_flush_unused_tables();
|
||||
TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db,
|
||||
const char *table_name,
|
||||
bool no_error);
|
||||
@ -395,7 +309,6 @@ extern "C" int simple_raw_key_cmp(void* arg, const void* key1,
|
||||
extern "C" int count_distinct_walk(void *elem, element_count count, void *arg);
|
||||
int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2);
|
||||
|
||||
extern TABLE *unused_tables;
|
||||
extern Item **not_found_item;
|
||||
extern Field *not_found_field;
|
||||
extern Field *view_ref_found;
|
||||
|
@ -110,7 +110,7 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
|
||||
|
||||
if (error == ETIMEDOUT || error == ETIME)
|
||||
{
|
||||
tdc_flush_unused_tables();
|
||||
tc_purge();
|
||||
error = 0;
|
||||
reset_flush_time = TRUE;
|
||||
}
|
||||
|
@ -1600,8 +1600,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
(int) thread_count, (ulong) thd->query_id,
|
||||
current_global_status_var->long_query_count,
|
||||
current_global_status_var->opened_tables,
|
||||
refresh_version,
|
||||
cached_open_tables(),
|
||||
tdc_refresh_version(),
|
||||
tc_records(),
|
||||
(uint) (queries_per_second1000 / 1000),
|
||||
(uint) (queries_per_second1000 % 1000));
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
|
@ -4424,7 +4424,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
|
||||
goto end;
|
||||
}
|
||||
|
||||
share= get_table_share_shortlived(thd, &table_list, GTS_TABLE | GTS_VIEW);
|
||||
share= tdc_acquire_share_shortlived(thd, &table_list, GTS_TABLE | GTS_VIEW);
|
||||
if (!share)
|
||||
{
|
||||
res= 0;
|
||||
@ -4476,9 +4476,7 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables,
|
||||
|
||||
|
||||
end_share:
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
release_table_share(share);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
tdc_release_share(share);
|
||||
|
||||
end:
|
||||
/*
|
||||
|
@ -2432,7 +2432,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
{
|
||||
char *end;
|
||||
/*
|
||||
It could happen that table's share in the table_def_cache
|
||||
It could happen that table's share in the table definition cache
|
||||
is the only thing that keeps the engine plugin loaded
|
||||
(if it is uninstalled and waits for the ref counter to drop to 0).
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "sql_priv.h"
|
||||
#include "unireg.h"
|
||||
#include "sql_test.h"
|
||||
#include "sql_base.h" // table_def_cache, table_cache_count, unused_tables
|
||||
#include "sql_base.h" // unused_tables
|
||||
#include "sql_show.h" // calc_sum_of_all_status
|
||||
#include "sql_select.h"
|
||||
#include "keycaches.h"
|
||||
@ -78,21 +78,21 @@ print_where(COND *cond,const char *info, enum_query_type query_type)
|
||||
|
||||
static void print_cached_tables(void)
|
||||
{
|
||||
uint idx,count,unused;
|
||||
uint count= 0, unused= 0;
|
||||
TABLE_SHARE *share;
|
||||
TABLE *start_link, *lnk, *entry;
|
||||
TDC_iterator tdc_it;
|
||||
|
||||
compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions));
|
||||
|
||||
/* purecov: begin tested */
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
puts("DB Table Version Thread Open Lock");
|
||||
|
||||
for (idx=unused=0 ; idx < table_def_cache.records ; idx++)
|
||||
tdc_it.init();
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
while ((share= tdc_it.next()))
|
||||
{
|
||||
share= (TABLE_SHARE*) my_hash_element(&table_def_cache, idx);
|
||||
|
||||
TABLE_SHARE::TABLE_list::Iterator it(share->used_tables);
|
||||
TABLE_SHARE::TABLE_list::Iterator it(share->tdc.used_tables);
|
||||
while ((entry= it++))
|
||||
{
|
||||
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
|
||||
@ -100,7 +100,7 @@ static void print_cached_tables(void)
|
||||
entry->in_use->thread_id, entry->db_stat ? 1 : 0,
|
||||
lock_descriptions[(int)entry->reginfo.lock_type]);
|
||||
}
|
||||
it.init(share->free_tables);
|
||||
it.init(share->tdc.free_tables);
|
||||
while ((entry= it++))
|
||||
{
|
||||
unused++;
|
||||
@ -109,7 +109,7 @@ static void print_cached_tables(void)
|
||||
0L, entry->db_stat ? 1 : 0, "Not in use");
|
||||
}
|
||||
}
|
||||
count=0;
|
||||
tdc_it.deinit();
|
||||
if ((start_link=lnk=unused_tables))
|
||||
{
|
||||
do
|
||||
@ -119,20 +119,18 @@ static void print_cached_tables(void)
|
||||
printf("unused_links isn't linked properly\n");
|
||||
return;
|
||||
}
|
||||
} while (count++ < cached_open_tables() && (lnk=lnk->next) != start_link);
|
||||
} while (count++ < tc_records() && (lnk=lnk->next) != start_link);
|
||||
if (lnk != start_link)
|
||||
{
|
||||
printf("Unused_links aren't connected\n");
|
||||
}
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
if (count != unused)
|
||||
printf("Unused_links (%d) doesn't match table_def_cache: %d\n", count,
|
||||
unused);
|
||||
printf("\nCurrent refresh version: %ld\n",refresh_version);
|
||||
if (my_hash_check(&table_def_cache))
|
||||
printf("Error: Table definition hash table is corrupted\n");
|
||||
printf("\nCurrent refresh version: %ld\n", tdc_refresh_version());
|
||||
fflush(stdout);
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
/* purecov: end */
|
||||
return;
|
||||
}
|
||||
@ -485,7 +483,7 @@ static void display_table_locks(void)
|
||||
DYNAMIC_ARRAY saved_table_locks;
|
||||
|
||||
(void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),
|
||||
cached_open_tables() + 20, 50,
|
||||
tc_records() + 20, 50,
|
||||
MYF(MY_THREAD_SPECIFIC));
|
||||
mysql_mutex_lock(&THR_LOCK_lock);
|
||||
for (list= thr_lock_thread_list; list; list= list_rest(list))
|
||||
@ -616,7 +614,7 @@ Open tables: %10lu\n\
|
||||
Open files: %10lu\n\
|
||||
Open streams: %10lu\n",
|
||||
tmp.opened_tables,
|
||||
(ulong) cached_open_tables(),
|
||||
(ulong) tc_records(),
|
||||
(ulong) my_file_opened,
|
||||
(ulong) my_stream_opened);
|
||||
|
||||
|
@ -2675,16 +2675,25 @@ static Sys_var_charptr Sys_system_time_zone(
|
||||
static Sys_var_ulong Sys_table_def_size(
|
||||
"table_definition_cache",
|
||||
"The number of cached table definitions",
|
||||
GLOBAL_VAR(table_def_size), CMD_LINE(REQUIRED_ARG),
|
||||
GLOBAL_VAR(tdc_size), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(TABLE_DEF_CACHE_MIN, 512*1024),
|
||||
DEFAULT(TABLE_DEF_CACHE_DEFAULT), BLOCK_SIZE(1));
|
||||
|
||||
static Sys_var_ulong Sys_table_cache_size(
|
||||
"table_open_cache", "The number of cached open tables",
|
||||
GLOBAL_VAR(table_cache_size), CMD_LINE(REQUIRED_ARG),
|
||||
GLOBAL_VAR(tc_size), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(1, 512*1024), DEFAULT(TABLE_OPEN_CACHE_DEFAULT),
|
||||
BLOCK_SIZE(1));
|
||||
|
||||
static ulong table_cache_instances;
|
||||
static Sys_var_ulong Sys_table_cache_instances(
|
||||
"table_open_cache_instances",
|
||||
"MySQL 5.6 compatible option. Not used or needed in MariaDB",
|
||||
READ_ONLY GLOBAL_VAR(table_cache_instances), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(1, 64), DEFAULT(1),
|
||||
BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL),
|
||||
ON_UPDATE(NULL), NULL);
|
||||
|
||||
static Sys_var_ulong Sys_thread_cache_size(
|
||||
"thread_cache_size",
|
||||
"How many threads we should keep in a cache for reuse",
|
||||
|
97
sql/table.cc
97
sql/table.cc
@ -31,7 +31,7 @@
|
||||
#include "sql_partition.h" // mysql_unpack_partition,
|
||||
// fix_partition_func, partition_info
|
||||
#include "sql_acl.h" // *_ACL, acl_getroot_no_password
|
||||
#include "sql_base.h" // release_table_share
|
||||
#include "sql_base.h"
|
||||
#include "create_options.h"
|
||||
#include <m_ctype.h>
|
||||
#include "my_md5.h"
|
||||
@ -318,23 +318,9 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
|
||||
/* TEMPORARY FIX: if true, this means this is mysql.gtid_slave_pos table */
|
||||
share->is_gtid_slave_pos= FALSE;
|
||||
share->table_category= get_table_category(& share->db, & share->table_name);
|
||||
share->version= refresh_version;
|
||||
share->open_errno= ENOENT;
|
||||
|
||||
/*
|
||||
Since alloc_table_share() can be called without any locking (for
|
||||
example, ha_create_table... functions), we do not assign a table
|
||||
map id here. Instead we assign a value that is not used
|
||||
elsewhere, and then assign a table map id inside open_table()
|
||||
under the protection of the LOCK_open mutex.
|
||||
*/
|
||||
share->table_map_id= ~0UL;
|
||||
share->cached_row_logging_check= -1;
|
||||
|
||||
share->used_tables.empty();
|
||||
share->free_tables.empty();
|
||||
share->m_flush_tickets.empty();
|
||||
|
||||
init_sql_alloc(&share->stats_cb.mem_root, TABLE_ALLOC_BLOCK_SIZE, 0, MYF(0));
|
||||
|
||||
memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
|
||||
@ -342,6 +328,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
|
||||
&share->LOCK_share, MY_MUTEX_INIT_SLOW);
|
||||
mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
|
||||
&share->LOCK_ha_data, MY_MUTEX_INIT_FAST);
|
||||
tdc_init_share(share);
|
||||
}
|
||||
DBUG_RETURN(share);
|
||||
}
|
||||
@ -354,7 +341,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name,
|
||||
init_tmp_table_share()
|
||||
thd thread handle
|
||||
share Share to fill
|
||||
key Table_cache_key, as generated from create_table_def_key.
|
||||
key Table_cache_key, as generated from tdc_create_key.
|
||||
must start with db name.
|
||||
key_length Length of key
|
||||
table_name Table name
|
||||
@ -404,11 +391,6 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
|
||||
compatibility checks.
|
||||
*/
|
||||
share->table_map_id= (ulong) thd->query_id;
|
||||
|
||||
share->used_tables.empty();
|
||||
share->free_tables.empty();
|
||||
share->m_flush_tickets.empty();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -443,6 +425,7 @@ void TABLE_SHARE::destroy()
|
||||
{
|
||||
mysql_mutex_destroy(&LOCK_share);
|
||||
mysql_mutex_destroy(&LOCK_ha_data);
|
||||
tdc_deinit_share(this);
|
||||
}
|
||||
my_hash_free(&name_hash);
|
||||
|
||||
@ -487,37 +470,7 @@ void free_table_share(TABLE_SHARE *share)
|
||||
{
|
||||
DBUG_ENTER("free_table_share");
|
||||
DBUG_PRINT("enter", ("table: %s.%s", share->db.str, share->table_name.str));
|
||||
DBUG_ASSERT(share->ref_count == 0);
|
||||
|
||||
if (share->m_flush_tickets.is_empty())
|
||||
{
|
||||
/*
|
||||
No threads are waiting for this share to be flushed (the
|
||||
share is not old, is for a temporary table, or just nobody
|
||||
happens to be waiting for it). Destroy it.
|
||||
*/
|
||||
share->destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
Wait_for_flush_list::Iterator it(share->m_flush_tickets);
|
||||
Wait_for_flush *ticket;
|
||||
/*
|
||||
We're about to iterate over a list that is used
|
||||
concurrently. Make sure this never happens without a lock.
|
||||
*/
|
||||
mysql_mutex_assert_owner(&LOCK_open);
|
||||
|
||||
while ((ticket= it++))
|
||||
(void) ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED);
|
||||
/*
|
||||
If there are threads waiting for this share to be flushed,
|
||||
the last one to receive the notification will destroy the
|
||||
share. At this point the share is removed from the table
|
||||
definition cache, so is OK to proceed here without waiting
|
||||
for this thread to do the work.
|
||||
*/
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -596,7 +549,7 @@ inline bool is_system_table_name(const char *name, uint length)
|
||||
|
||||
NOTES
|
||||
This function is called when the table definition is not cached in
|
||||
table_def_cache
|
||||
table definition cache
|
||||
The data is returned in 'share', which is alloced by
|
||||
alloc_table_share().. The code assumes that share is initialized.
|
||||
*/
|
||||
@ -2932,7 +2885,7 @@ int closefrm(register TABLE *table, bool free_share)
|
||||
if (free_share)
|
||||
{
|
||||
if (table->s->tmp_table == NO_TMP_TABLE)
|
||||
release_table_share(table->s);
|
||||
tdc_release_share(table->s);
|
||||
else
|
||||
free_table_share(table->s);
|
||||
}
|
||||
@ -3775,7 +3728,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
|
||||
if (gvisitor->m_lock_open_count++ == 0)
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
|
||||
TABLE_list::Iterator tables_it(used_tables);
|
||||
TABLE_list::Iterator tables_it(tdc.used_tables);
|
||||
|
||||
/*
|
||||
In case of multiple searches running in parallel, avoid going
|
||||
@ -3829,10 +3782,15 @@ end:
|
||||
@param abstime Timeout for waiting as absolute time value.
|
||||
@param deadlock_weight Weight of this wait for deadlock detector.
|
||||
|
||||
@pre LOCK_open is write locked, the share is used (has
|
||||
non-zero reference count), is marked for flush and
|
||||
@pre LOCK_table_share is locked, the share is marked for flush and
|
||||
this connection does not reference the share.
|
||||
LOCK_open will be unlocked temporarily during execution.
|
||||
LOCK_table_share will be unlocked temporarily during execution.
|
||||
|
||||
It may happen that another FLUSH TABLES thread marked this share
|
||||
for flush, but didn't yet purge it from table definition cache.
|
||||
In this case we may start waiting for a table share that has no
|
||||
references (ref_count == 0). We do this with assumption that this
|
||||
another FLUSH TABLES thread is about to purge this share.
|
||||
|
||||
@retval FALSE - Success.
|
||||
@retval TRUE - Error (OOM, deadlock, timeout, etc...).
|
||||
@ -3845,19 +3803,14 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
|
||||
Wait_for_flush ticket(mdl_context, this, deadlock_weight);
|
||||
MDL_wait::enum_wait_status wait_status;
|
||||
|
||||
mysql_mutex_assert_owner(&LOCK_open);
|
||||
/*
|
||||
We should enter this method only when share's version is not
|
||||
up to date and the share is referenced. Otherwise our
|
||||
thread will never be woken up from wait.
|
||||
*/
|
||||
DBUG_ASSERT(version != refresh_version && ref_count != 0);
|
||||
mysql_mutex_assert_owner(&tdc.LOCK_table_share);
|
||||
DBUG_ASSERT(has_old_version());
|
||||
|
||||
m_flush_tickets.push_front(&ticket);
|
||||
tdc.m_flush_tickets.push_front(&ticket);
|
||||
|
||||
mdl_context->m_wait.reset_status();
|
||||
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
mysql_mutex_unlock(&tdc.LOCK_table_share);
|
||||
|
||||
mdl_context->will_wait_for(&ticket);
|
||||
|
||||
@ -3868,18 +3821,22 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
|
||||
|
||||
mdl_context->done_waiting_for();
|
||||
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
mysql_mutex_lock(&tdc.LOCK_table_share);
|
||||
|
||||
m_flush_tickets.remove(&ticket);
|
||||
tdc.m_flush_tickets.remove(&ticket);
|
||||
|
||||
if (m_flush_tickets.is_empty() && ref_count == 0)
|
||||
if (tdc.m_flush_tickets.is_empty() && tdc.ref_count == 0)
|
||||
{
|
||||
/*
|
||||
If our thread was the last one using the share,
|
||||
we must destroy it here.
|
||||
*/
|
||||
mysql_mutex_unlock(&tdc.LOCK_table_share);
|
||||
destroy();
|
||||
}
|
||||
else
|
||||
mysql_mutex_unlock(&tdc.LOCK_table_share);
|
||||
|
||||
|
||||
/*
|
||||
In cases when our wait was aborted by KILL statement,
|
||||
@ -3924,7 +3881,7 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
|
||||
|
||||
void TABLE::init(THD *thd, TABLE_LIST *tl)
|
||||
{
|
||||
DBUG_ASSERT(s->ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
|
||||
DBUG_ASSERT(s->tdc.ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
|
||||
|
||||
if (thd->lex->need_correct_ident())
|
||||
alias_name_used= my_strcasecmp(table_alias_charset,
|
||||
|
26
sql/table.h
26
sql/table.h
@ -479,7 +479,7 @@ TABLE_CATEGORY get_table_category(const LEX_STRING *db,
|
||||
|
||||
struct TABLE_share;
|
||||
|
||||
extern ulong refresh_version;
|
||||
extern ulong tdc_refresh_version(void);
|
||||
|
||||
typedef struct st_table_field_type
|
||||
{
|
||||
@ -599,15 +599,27 @@ struct TABLE_SHARE
|
||||
TYPELIB *intervals; /* pointer to interval info */
|
||||
mysql_mutex_t LOCK_ha_data; /* To protect access to ha_data */
|
||||
mysql_mutex_t LOCK_share; /* To protect TABLE_SHARE */
|
||||
TABLE_SHARE *next, **prev; /* Link to unused shares */
|
||||
|
||||
typedef I_P_List <TABLE, TABLE_share> TABLE_list;
|
||||
struct
|
||||
{
|
||||
/**
|
||||
Protects ref_count and m_flush_tickets.
|
||||
*/
|
||||
mysql_mutex_t LOCK_table_share;
|
||||
TABLE_SHARE *next, **prev; /* Link to unused shares */
|
||||
uint ref_count; /* How many TABLE objects uses this */
|
||||
/**
|
||||
List of tickets representing threads waiting for the share to be flushed.
|
||||
*/
|
||||
Wait_for_flush_list m_flush_tickets;
|
||||
/*
|
||||
Doubly-linked (back-linked) lists of used and unused TABLE objects
|
||||
for this share.
|
||||
*/
|
||||
typedef I_P_List <TABLE, TABLE_share> TABLE_list;
|
||||
TABLE_list used_tables;
|
||||
TABLE_list free_tables;
|
||||
} tdc;
|
||||
|
||||
LEX_CUSTRING tabledef_version;
|
||||
|
||||
@ -674,7 +686,6 @@ struct TABLE_SHARE
|
||||
/** Per-page checksums or not. */
|
||||
enum ha_choice page_checksum;
|
||||
|
||||
uint ref_count; /* How many TABLE objects uses this */
|
||||
uint key_block_size; /* create key_block_size, if used */
|
||||
uint stats_sample_pages; /* number of pages to sample during
|
||||
stats estimation, if used, otherwise 0. */
|
||||
@ -759,11 +770,6 @@ struct TABLE_SHARE
|
||||
/** Instrumentation for this table share. */
|
||||
PSI_table_share *m_psi;
|
||||
|
||||
/**
|
||||
List of tickets representing threads waiting for the share to be flushed.
|
||||
*/
|
||||
Wait_for_flush_list m_flush_tickets;
|
||||
|
||||
/*
|
||||
Set share's table cache key and update its db and table name appropriately.
|
||||
|
||||
@ -835,7 +841,7 @@ struct TABLE_SHARE
|
||||
/** Is this table share being expelled from the table definition cache? */
|
||||
inline bool has_old_version() const
|
||||
{
|
||||
return version != refresh_version;
|
||||
return version != tdc_refresh_version();
|
||||
}
|
||||
|
||||
/**
|
||||
|
1280
sql/table_cache.cc
Normal file
1280
sql/table_cache.cc
Normal file
File diff suppressed because it is too large
Load Diff
134
sql/table_cache.h
Normal file
134
sql/table_cache.h
Normal file
@ -0,0 +1,134 @@
|
||||
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
|
||||
Copyright (c) 2010, 2011 Monty Program Ab
|
||||
Copyright (C) 2013 Sergey Vojtovich and MariaDB Foundation
|
||||
|
||||
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 St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
|
||||
enum enum_tdc_remove_table_type
|
||||
{
|
||||
TDC_RT_REMOVE_ALL,
|
||||
TDC_RT_REMOVE_NOT_OWN,
|
||||
TDC_RT_REMOVE_UNUSED,
|
||||
TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE
|
||||
};
|
||||
|
||||
extern ulong tdc_size;
|
||||
extern ulong tc_size;
|
||||
extern TABLE *unused_tables; /* FIXME: make private */
|
||||
extern mysql_mutex_t LOCK_open; /* FIXME: make private */
|
||||
|
||||
extern int tdc_init(void);
|
||||
extern void tdc_start_shutdown(void);
|
||||
extern void tdc_deinit(void);
|
||||
extern ulong tdc_records(void);
|
||||
extern void tdc_purge(bool all);
|
||||
extern void tdc_init_share(TABLE_SHARE *share);
|
||||
extern void tdc_deinit_share(TABLE_SHARE *share);
|
||||
extern TABLE_SHARE *tdc_lock_share(const char *db, const char *table_name);
|
||||
extern void tdc_unlock_share(TABLE_SHARE *share);
|
||||
extern TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db,
|
||||
const char *table_name,
|
||||
const char *key, uint key_length,
|
||||
uint flags, TABLE **out_table);
|
||||
extern void tdc_release_share(TABLE_SHARE *share);
|
||||
extern bool tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type,
|
||||
const char *db, const char *table_name,
|
||||
bool kill_delayed_threads);
|
||||
extern int tdc_wait_for_old_version(THD *thd, const char *db,
|
||||
const char *table_name,
|
||||
ulong wait_timeout, uint deadlock_weight);
|
||||
extern ulong tdc_refresh_version(void);
|
||||
extern void tdc_increment_refresh_version(void);
|
||||
extern void tdc_assign_new_table_id(TABLE_SHARE *share);
|
||||
|
||||
extern uint tc_records(void);
|
||||
extern void tc_purge(void);
|
||||
extern void tc_add_table(THD *thd, TABLE *table);
|
||||
extern bool tc_release_table(TABLE *table);
|
||||
|
||||
/**
|
||||
Create a table cache key for non-temporary table.
|
||||
|
||||
@param key Buffer for key (must be at least NAME_LEN*2+2 bytes).
|
||||
@param db Database name.
|
||||
@param table_name Table name.
|
||||
|
||||
@return Length of key.
|
||||
*/
|
||||
|
||||
inline uint tdc_create_key(char *key, const char *db, const char *table_name)
|
||||
{
|
||||
/*
|
||||
In theory caller should ensure that both db and table_name are
|
||||
not longer than NAME_LEN bytes. In practice we play safe to avoid
|
||||
buffer overruns.
|
||||
*/
|
||||
return (uint) (strmake(strmake(key, db, NAME_LEN) + 1, table_name,
|
||||
NAME_LEN) - key + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
Convenience helper: call tdc_acquire_share() without out_table.
|
||||
*/
|
||||
|
||||
static inline TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db,
|
||||
const char *table_name,
|
||||
const char *key,
|
||||
uint key_length, uint flags)
|
||||
{
|
||||
return tdc_acquire_share(thd, db, table_name, key, key_length, flags, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convenience helper: call tdc_acquire_share() without precomputed cache key.
|
||||
*/
|
||||
|
||||
static inline TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db,
|
||||
const char *table_name, uint flags)
|
||||
{
|
||||
char key[MAX_DBKEY_LENGTH];
|
||||
uint key_length;
|
||||
key_length= tdc_create_key(key, db, table_name);
|
||||
return tdc_acquire_share(thd, db, table_name, key, key_length, flags);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convenience helper: call tdc_acquire_share() reusing the MDL cache key.
|
||||
|
||||
@note lifetime of the returned TABLE_SHARE is limited by the
|
||||
lifetime of the TABLE_LIST object!!!
|
||||
*/
|
||||
|
||||
uint get_table_def_key(const TABLE_LIST *table_list, const char **key);
|
||||
|
||||
static inline TABLE_SHARE *tdc_acquire_share_shortlived(THD *thd, TABLE_LIST *tl,
|
||||
uint flags)
|
||||
{
|
||||
const char *key;
|
||||
uint key_length= get_table_def_key(tl, &key);
|
||||
return tdc_acquire_share(thd, tl->db, tl->table_name, key, key_length, flags);
|
||||
}
|
||||
|
||||
|
||||
class TDC_iterator
|
||||
{
|
||||
ulong idx;
|
||||
public:
|
||||
void init(void);
|
||||
void deinit(void);
|
||||
TABLE_SHARE *next(void);
|
||||
};
|
@ -3220,7 +3220,7 @@ int ha_connect::delete_or_rename_table(const char *name, const char *to)
|
||||
*tabname == '#')
|
||||
goto fin;
|
||||
|
||||
key_length= create_table_def_key(key, db, tabname);
|
||||
key_length= tdc_create_key(key, db, tabname);
|
||||
|
||||
// share contains the option struct that we need
|
||||
if (!(share= alloc_table_share(db, tabname, key, key_length)))
|
||||
|
@ -40,6 +40,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <my_base.h> // HA_OPTION_*
|
||||
#include <mysys_err.h>
|
||||
#include <innodb_priv.h>
|
||||
#include <table_cache.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
@ -1705,16 +1706,16 @@ innobase_get_stmt(
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Get the current setting of the table_def_size global parameter. We do
|
||||
Get the current setting of the tdc_size global parameter. We do
|
||||
a dirty read because for one there is no synchronization object and
|
||||
secondly there is little harm in doing so even if we get a torn read.
|
||||
@return value of table_def_size */
|
||||
@return value of tdc_size */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
innobase_get_table_cache_size(void)
|
||||
/*===============================*/
|
||||
{
|
||||
return(table_def_size);
|
||||
return(tdc_size);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
@ -3154,8 +3155,8 @@ innobase_change_buffering_inited_ok:
|
||||
|
||||
if (innobase_open_files < 10) {
|
||||
innobase_open_files = 300;
|
||||
if (srv_file_per_table && table_cache_size > 300) {
|
||||
innobase_open_files = table_cache_size;
|
||||
if (srv_file_per_table && tc_size > 300) {
|
||||
innobase_open_files = tc_size;
|
||||
}
|
||||
}
|
||||
srv_max_n_open_files = (ulint) innobase_open_files;
|
||||
|
Loading…
x
Reference in New Issue
Block a user