mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
MDEV-7324 - Lock-free hash for table definition cache
This commit is contained in:
parent
8883c54ac0
commit
6dbc48ca79
22 changed files with 911 additions and 773 deletions
|
@ -231,6 +231,9 @@ void lf_hash_init(LF_HASH *hash, uint element_size, uint flags,
|
|||
void lf_hash_destroy(LF_HASH *hash);
|
||||
int lf_hash_insert(LF_HASH *hash, LF_PINS *pins, const void *data);
|
||||
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen);
|
||||
void *lf_hash_search_using_hash_value(LF_HASH *hash, LF_PINS *pins,
|
||||
my_hash_value_type hash_value,
|
||||
const void *key, uint keylen);
|
||||
int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen);
|
||||
int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins,
|
||||
my_hash_walk_action action, void *argument);
|
||||
|
|
|
@ -2119,9 +2119,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
call proc_1();
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
|
@ -2132,9 +2132,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
call proc_1();
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
|
@ -2145,9 +2145,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
call proc_1();
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
|
@ -2158,9 +2158,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
flush tables;
|
||||
create function func_1() returns int begin flush tables; return 1; end|
|
||||
ERROR 0A000: FLUSH is not allowed in stored function or trigger
|
||||
|
@ -2176,9 +2176,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
prepare abc from "flush tables";
|
||||
execute abc;
|
||||
show open tables from mysql;
|
||||
|
@ -2190,9 +2190,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
execute abc;
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
|
@ -2203,9 +2203,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
execute abc;
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
|
@ -2216,9 +2216,9 @@ select Host, Db from mysql.host limit 0;
|
|||
Host Db
|
||||
show open tables from mysql;
|
||||
Database Table In_use Name_locked
|
||||
mysql user 0 0
|
||||
mysql general_log 0 0
|
||||
mysql host 0 0
|
||||
mysql user 0 0
|
||||
flush tables;
|
||||
deallocate prepare abc;
|
||||
create procedure proc_1() flush logs;
|
||||
|
|
|
@ -259,8 +259,8 @@ create table t1(n int);
|
|||
insert into t1 values (1);
|
||||
show open tables;
|
||||
Database Table In_use Name_locked
|
||||
test t1 0 0
|
||||
mysql general_log 0 0
|
||||
test t1 0 0
|
||||
drop table t1;
|
||||
create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" ENGINE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
|
||||
show create table t1;
|
||||
|
|
|
@ -24,11 +24,11 @@ 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 (
|
||||
|
|
|
@ -5,9 +5,9 @@ WHERE name LIKE 'wait/synch/mutex/%'
|
|||
truncate table performance_schema.events_statements_summary_by_digest;
|
||||
flush status;
|
||||
select NAME from performance_schema.mutex_instances
|
||||
where NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share' GROUP BY NAME;
|
||||
where NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex' GROUP BY NAME;
|
||||
NAME
|
||||
wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share
|
||||
wait/synch/mutex/mysys/THR_LOCK::mutex
|
||||
select NAME from performance_schema.rwlock_instances
|
||||
where NAME = 'wait/synch/rwlock/sql/LOCK_grant';
|
||||
NAME
|
||||
|
@ -24,7 +24,7 @@ id b
|
|||
1 initial value
|
||||
SET @before_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
SELECT * FROM t1;
|
||||
id b
|
||||
1 initial value
|
||||
|
@ -37,12 +37,12 @@ id b
|
|||
8 initial value
|
||||
SET @after_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
SELECT IF((@after_count - @before_count) > 0, 'Success', 'Failure') test_fm1_timed;
|
||||
test_fm1_timed
|
||||
Success
|
||||
UPDATE performance_schema.setup_instruments SET enabled = 'NO'
|
||||
WHERE NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share';
|
||||
WHERE NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex';
|
||||
TRUNCATE TABLE performance_schema.events_waits_history_long;
|
||||
TRUNCATE TABLE performance_schema.events_waits_history;
|
||||
TRUNCATE TABLE performance_schema.events_waits_current;
|
||||
|
@ -51,7 +51,7 @@ id b
|
|||
1 initial value
|
||||
SET @before_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
SELECT * FROM t1;
|
||||
id b
|
||||
1 initial value
|
||||
|
@ -64,7 +64,7 @@ id b
|
|||
8 initial value
|
||||
SET @after_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_fm2_timed;
|
||||
test_fm2_timed
|
||||
Success
|
||||
|
|
|
@ -19,7 +19,7 @@ flush status;
|
|||
|
||||
# Make sure objects are instrumented
|
||||
select NAME from performance_schema.mutex_instances
|
||||
where NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share' GROUP BY NAME;
|
||||
where NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex' GROUP BY NAME;
|
||||
select NAME from performance_schema.rwlock_instances
|
||||
where NAME = 'wait/synch/rwlock/sql/LOCK_grant';
|
||||
|
||||
|
@ -49,18 +49,18 @@ SELECT * FROM t1 WHERE id = 1;
|
|||
|
||||
SET @before_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
|
||||
SELECT * FROM t1;
|
||||
|
||||
SET @after_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
|
||||
SELECT IF((@after_count - @before_count) > 0, 'Success', 'Failure') test_fm1_timed;
|
||||
|
||||
UPDATE performance_schema.setup_instruments SET enabled = 'NO'
|
||||
WHERE NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share';
|
||||
WHERE NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex';
|
||||
|
||||
TRUNCATE TABLE performance_schema.events_waits_history_long;
|
||||
TRUNCATE TABLE performance_schema.events_waits_history;
|
||||
|
@ -70,13 +70,13 @@ SELECT * FROM t1 WHERE id = 1;
|
|||
|
||||
SET @before_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
|
||||
SELECT * FROM t1;
|
||||
|
||||
SET @after_count = (SELECT SUM(TIMER_WAIT)
|
||||
FROM performance_schema.events_waits_history_long
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/sql/TABLE_SHARE::tdc.LOCK_table_share'));
|
||||
WHERE (EVENT_NAME = 'wait/synch/mutex/mysys/THR_LOCK::mutex'));
|
||||
|
||||
SELECT IF((COALESCE(@after_count, 0) - COALESCE(@before_count, 0)) = 0, 'Success', 'Failure') test_fm2_timed;
|
||||
|
||||
|
|
|
@ -2224,24 +2224,32 @@ deallocate prepare abc;
|
|||
|
||||
create procedure proc_1() flush tables;
|
||||
flush tables;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
call proc_1();
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
call proc_1();
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
call proc_1();
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
flush tables;
|
||||
delimiter |;
|
||||
|
@ -2261,24 +2269,31 @@ drop procedure proc_1;
|
|||
flush tables;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
--enable_ps_protocol
|
||||
|
||||
prepare abc from "flush tables";
|
||||
execute abc;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
execute abc;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
execute abc;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
select Host, User from mysql.user limit 0;
|
||||
select Host, Db from mysql.host limit 0;
|
||||
--sorted_result
|
||||
show open tables from mysql;
|
||||
flush tables;
|
||||
deallocate prepare abc;
|
||||
|
|
|
@ -135,9 +135,11 @@ show create table t1;
|
|||
drop table t1;
|
||||
|
||||
flush tables;
|
||||
--sorted_result
|
||||
show open tables;
|
||||
create table t1(n int);
|
||||
insert into t1 values (1);
|
||||
--sorted_result
|
||||
show open tables;
|
||||
drop table t1;
|
||||
|
||||
|
@ -617,6 +619,7 @@ show databases;
|
|||
show tables;
|
||||
show events;
|
||||
show table status;
|
||||
--sorted_result
|
||||
show open tables;
|
||||
show plugins;
|
||||
show columns in t1;
|
||||
|
|
|
@ -122,7 +122,7 @@ retry:
|
|||
{
|
||||
if (unlikely(callback))
|
||||
{
|
||||
if (callback(cursor->curr + 1, (void*)key))
|
||||
if (cur_hashnr & 1 && callback(cursor->curr + 1, (void*)key))
|
||||
return 1;
|
||||
}
|
||||
else if (cur_hashnr >= hashnr)
|
||||
|
@ -467,12 +467,13 @@ int lf_hash_delete(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
|||
NOTE
|
||||
see lsearch() for pin usage notes
|
||||
*/
|
||||
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
||||
void *lf_hash_search_using_hash_value(LF_HASH *hash, LF_PINS *pins,
|
||||
my_hash_value_type hashnr,
|
||||
const void *key, uint keylen)
|
||||
{
|
||||
LF_SLIST * volatile *el, *found;
|
||||
uint bucket, hashnr= calc_hash(hash, (uchar *)key, keylen);
|
||||
uint bucket= hashnr % hash->size;
|
||||
|
||||
bucket= hashnr % hash->size;
|
||||
lf_rwlock_by_pins(pins);
|
||||
el= _lf_dynarray_lvalue(&hash->array, bucket);
|
||||
if (unlikely(!el))
|
||||
|
@ -521,6 +522,13 @@ int lf_hash_iterate(LF_HASH *hash, LF_PINS *pins,
|
|||
return res;
|
||||
}
|
||||
|
||||
void *lf_hash_search(LF_HASH *hash, LF_PINS *pins, const void *key, uint keylen)
|
||||
{
|
||||
return lf_hash_search_using_hash_value(hash, pins,
|
||||
calc_hash(hash, (uchar*) key, keylen),
|
||||
key, keylen);
|
||||
}
|
||||
|
||||
static const uchar *dummy_key= (uchar*)"";
|
||||
|
||||
/*
|
||||
|
|
|
@ -5001,12 +5001,12 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name,
|
|||
else if (engines_with_discover)
|
||||
hton= &dummy;
|
||||
|
||||
TABLE_SHARE *share= tdc_lock_share(db, table_name);
|
||||
if (share)
|
||||
TDC_element *element= tdc_lock_share(thd, db, table_name);
|
||||
if (element && element != MY_ERRPTR)
|
||||
{
|
||||
if (hton)
|
||||
*hton= share->db_type();
|
||||
tdc_unlock_share(share);
|
||||
*hton= element->share->db_type();
|
||||
tdc_unlock_share(element);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
|
|
@ -4789,7 +4789,8 @@ static int init_server_components()
|
|||
all things are initialized so that unireg_abort() doesn't fail
|
||||
*/
|
||||
mdl_init();
|
||||
if (tdc_init() | hostname_cache_init())
|
||||
tdc_init();
|
||||
if (hostname_cache_init())
|
||||
unireg_abort(1);
|
||||
|
||||
query_cache_set_min_res_unit(query_cache_min_res_unit);
|
||||
|
|
289
sql/sql_base.cc
289
sql/sql_base.cc
|
@ -270,58 +270,75 @@ uint get_table_def_key(const TABLE_LIST *table_list, const char **key)
|
|||
# Pointer to list of names of open tables.
|
||||
*/
|
||||
|
||||
struct list_open_tables_arg
|
||||
{
|
||||
THD *thd;
|
||||
const char *db;
|
||||
const char *wild;
|
||||
TABLE_LIST table_list;
|
||||
OPEN_TABLE_LIST **start_list, *open_list;
|
||||
};
|
||||
|
||||
|
||||
static my_bool list_open_tables_callback(TDC_element *element,
|
||||
list_open_tables_arg *arg)
|
||||
{
|
||||
char *db= (char*) element->m_key;
|
||||
char *table_name= (char*) element->m_key + strlen((char*) element->m_key) + 1;
|
||||
|
||||
if (arg->db && my_strcasecmp(system_charset_info, arg->db, db))
|
||||
return FALSE;
|
||||
if (arg->wild && wild_compare(table_name, arg->wild, 0))
|
||||
return FALSE;
|
||||
|
||||
/* Check if user has SELECT privilege for any column in the table */
|
||||
arg->table_list.db= db;
|
||||
arg->table_list.table_name= table_name;
|
||||
arg->table_list.grant.privilege= 0;
|
||||
|
||||
if (check_table_access(arg->thd, SELECT_ACL, &arg->table_list, TRUE, 1, TRUE))
|
||||
return FALSE;
|
||||
|
||||
if (!(*arg->start_list= (OPEN_TABLE_LIST *) arg->thd->alloc(
|
||||
sizeof(**arg->start_list) + element->m_key_length)))
|
||||
return TRUE;
|
||||
|
||||
strmov((*arg->start_list)->table=
|
||||
strmov(((*arg->start_list)->db= (char*) ((*arg->start_list) + 1)),
|
||||
db) + 1, table_name);
|
||||
(*arg->start_list)->in_use= 0;
|
||||
|
||||
mysql_mutex_lock(&element->LOCK_table_share);
|
||||
TDC_element::All_share_tables_list::Iterator it(element->all_tables);
|
||||
TABLE *table;
|
||||
while ((table= it++))
|
||||
if (table->in_use)
|
||||
++(*arg->start_list)->in_use;
|
||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||
(*arg->start_list)->locked= 0; /* Obsolete. */
|
||||
arg->start_list= &(*arg->start_list)->next;
|
||||
*arg->start_list= 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild)
|
||||
{
|
||||
OPEN_TABLE_LIST **start_list, *open_list;
|
||||
TABLE_LIST table_list;
|
||||
TABLE_SHARE *share;
|
||||
TDC_iterator tdc_it;
|
||||
list_open_tables_arg argument;
|
||||
DBUG_ENTER("list_open_tables");
|
||||
|
||||
bzero((char*) &table_list,sizeof(table_list));
|
||||
start_list= &open_list;
|
||||
open_list=0;
|
||||
argument.thd= thd;
|
||||
argument.db= db;
|
||||
argument.wild= wild;
|
||||
bzero((char*) &argument.table_list, sizeof(argument.table_list));
|
||||
argument.start_list= &argument.open_list;
|
||||
argument.open_list= 0;
|
||||
|
||||
tdc_it.init();
|
||||
while ((share= tdc_it.next()))
|
||||
{
|
||||
if (db && my_strcasecmp(system_charset_info, db, share->db.str))
|
||||
continue;
|
||||
if (wild && wild_compare(share->table_name.str, wild, 0))
|
||||
continue;
|
||||
if (tdc_iterate(thd, (my_hash_walk_action) list_open_tables_callback,
|
||||
&argument, true))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
/* Check if user has SELECT privilege for any column in the table */
|
||||
table_list.db= share->db.str;
|
||||
table_list.table_name= share->table_name.str;
|
||||
table_list.grant.privilege=0;
|
||||
|
||||
if (check_table_access(thd,SELECT_ACL,&table_list, TRUE, 1, TRUE))
|
||||
continue;
|
||||
|
||||
if (!(*start_list = (OPEN_TABLE_LIST *)
|
||||
sql_alloc(sizeof(**start_list)+share->table_cache_key.length)))
|
||||
{
|
||||
open_list=0; // Out of memory
|
||||
break;
|
||||
}
|
||||
strmov((*start_list)->table=
|
||||
strmov(((*start_list)->db= (char*) ((*start_list)+1)),
|
||||
share->db.str)+1,
|
||||
share->table_name.str);
|
||||
(*start_list)->in_use= 0;
|
||||
mysql_mutex_lock(&share->tdc.LOCK_table_share);
|
||||
TABLE_SHARE::All_share_tables_list::Iterator it(share->tdc.all_tables);
|
||||
TABLE *table;
|
||||
while ((table= it++))
|
||||
if (table->in_use)
|
||||
++(*start_list)->in_use;
|
||||
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
|
||||
(*start_list)->locked= 0; /* Obsolete. */
|
||||
start_list= &(*start_list)->next;
|
||||
*start_list=0;
|
||||
}
|
||||
tdc_it.deinit();
|
||||
DBUG_RETURN(open_list);
|
||||
DBUG_RETURN(argument.open_list);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -371,12 +388,12 @@ void free_io_cache(TABLE *table)
|
|||
@pre Caller should have TABLE_SHARE::tdc.LOCK_table_share mutex.
|
||||
*/
|
||||
|
||||
void kill_delayed_threads_for_table(TABLE_SHARE *share)
|
||||
void kill_delayed_threads_for_table(TDC_element *element)
|
||||
{
|
||||
TABLE_SHARE::All_share_tables_list::Iterator it(share->tdc.all_tables);
|
||||
TDC_element::All_share_tables_list::Iterator it(element->all_tables);
|
||||
TABLE *tab;
|
||||
|
||||
mysql_mutex_assert_owner(&share->tdc.LOCK_table_share);
|
||||
mysql_mutex_assert_owner(&element->LOCK_table_share);
|
||||
|
||||
if (!delayed_insert_threads)
|
||||
return;
|
||||
|
@ -385,7 +402,7 @@ void kill_delayed_threads_for_table(TABLE_SHARE *share)
|
|||
{
|
||||
THD *in_use= tab->in_use;
|
||||
|
||||
DBUG_ASSERT(in_use && tab->s->tdc.flushed);
|
||||
DBUG_ASSERT(in_use && tab->s->tdc->flushed);
|
||||
if ((in_use->system_thread & SYSTEM_THREAD_DELAYED_INSERT) &&
|
||||
! in_use->killed)
|
||||
{
|
||||
|
@ -422,6 +439,30 @@ void kill_delayed_threads_for_table(TABLE_SHARE *share)
|
|||
lock taken by thread trying to obtain global read lock.
|
||||
*/
|
||||
|
||||
|
||||
struct close_cached_tables_arg
|
||||
{
|
||||
ulong refresh_version;
|
||||
TDC_element *element;
|
||||
};
|
||||
|
||||
|
||||
static my_bool close_cached_tables_callback(TDC_element *element,
|
||||
close_cached_tables_arg *arg)
|
||||
{
|
||||
mysql_mutex_lock(&element->LOCK_table_share);
|
||||
if (element->share && element->flushed &&
|
||||
element->version < arg->refresh_version)
|
||||
{
|
||||
/* wait_for_old_version() will unlock mutex and free share */
|
||||
arg->element= element;
|
||||
return TRUE;
|
||||
}
|
||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool close_cached_tables(THD *thd, TABLE_LIST *tables,
|
||||
bool wait_for_refresh, ulong timeout)
|
||||
{
|
||||
|
@ -517,38 +558,21 @@ bool close_cached_tables(THD *thd, TABLE_LIST *tables,
|
|||
|
||||
if (!tables)
|
||||
{
|
||||
bool found= true;
|
||||
int r= 0;
|
||||
close_cached_tables_arg argument;
|
||||
argument.refresh_version= refresh_version;
|
||||
set_timespec(abstime, timeout);
|
||||
while (found && !thd->killed)
|
||||
{
|
||||
TABLE_SHARE *share;
|
||||
TDC_iterator tdc_it;
|
||||
found= false;
|
||||
|
||||
tdc_it.init();
|
||||
while ((share= tdc_it.next()))
|
||||
{
|
||||
mysql_mutex_lock(&share->tdc.LOCK_table_share);
|
||||
if (share->tdc.flushed && share->tdc.version < refresh_version)
|
||||
{
|
||||
/* wait_for_old_version() will unlock mutex and free share */
|
||||
found= true;
|
||||
break;
|
||||
}
|
||||
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
|
||||
}
|
||||
tdc_it.deinit();
|
||||
while (!thd->killed &&
|
||||
(r= tdc_iterate(thd,
|
||||
(my_hash_walk_action) close_cached_tables_callback,
|
||||
&argument)) == 1 &&
|
||||
!argument.element->share->wait_for_old_version(thd, &abstime,
|
||||
MDL_wait_for_subgraph::DEADLOCK_WEIGHT_DDL))
|
||||
/* no-op */;
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (share->wait_for_old_version(thd, &abstime,
|
||||
MDL_wait_for_subgraph::DEADLOCK_WEIGHT_DDL))
|
||||
{
|
||||
result= TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (r)
|
||||
result= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -592,53 +616,72 @@ err_with_reopen:
|
|||
if specified string is NULL, then any table with a connection string.
|
||||
*/
|
||||
|
||||
struct close_cached_connection_tables_arg
|
||||
{
|
||||
THD *thd;
|
||||
LEX_STRING *connection;
|
||||
TABLE_LIST *tables;
|
||||
};
|
||||
|
||||
|
||||
static my_bool close_cached_connection_tables_callback(
|
||||
TDC_element *element, close_cached_connection_tables_arg *arg)
|
||||
{
|
||||
TABLE_LIST *tmp;
|
||||
|
||||
mysql_mutex_lock(&element->LOCK_table_share);
|
||||
/* Ignore if table is not open or does not have a connect_string */
|
||||
if (!element->share || !element->share->connect_string.length ||
|
||||
!element->ref_count)
|
||||
{
|
||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Compare the connection string */
|
||||
if (arg->connection &&
|
||||
(arg->connection->length > element->share->connect_string.length ||
|
||||
(arg->connection->length < element->share->connect_string.length &&
|
||||
(element->share->connect_string.str[arg->connection->length] != '/' &&
|
||||
element->share->connect_string.str[arg->connection->length] != '\\')) ||
|
||||
strncasecmp(arg->connection->str, element->share->connect_string.str,
|
||||
arg->connection->length)))
|
||||
return FALSE;
|
||||
|
||||
/* close_cached_tables() only uses these elements */
|
||||
if (!(tmp= (TABLE_LIST*) alloc_root(arg->thd->mem_root, sizeof(TABLE_LIST))) ||
|
||||
!(tmp->db= strdup_root(arg->thd->mem_root, element->share->db.str)) ||
|
||||
!(tmp->table_name= strdup_root(arg->thd->mem_root,
|
||||
element->share->table_name.str)))
|
||||
return TRUE;
|
||||
|
||||
tmp->next_local= arg->tables;
|
||||
arg->tables= tmp;
|
||||
|
||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool close_cached_connection_tables(THD *thd, LEX_STRING *connection)
|
||||
{
|
||||
TABLE_LIST tmp, *tables= NULL;
|
||||
bool result= FALSE;
|
||||
TABLE_SHARE *share;
|
||||
TDC_iterator tdc_it;
|
||||
close_cached_connection_tables_arg argument;
|
||||
DBUG_ENTER("close_cached_connections");
|
||||
DBUG_ASSERT(thd);
|
||||
|
||||
bzero(&tmp, sizeof(TABLE_LIST));
|
||||
argument.thd= thd;
|
||||
argument.connection= connection;
|
||||
argument.tables= NULL;
|
||||
|
||||
tdc_it.init();
|
||||
while ((share= tdc_it.next()))
|
||||
{
|
||||
mysql_mutex_lock(&share->tdc.LOCK_table_share);
|
||||
/* Ignore if table is not open or does not have a connect_string */
|
||||
if (!share->connect_string.length || !share->tdc.ref_count)
|
||||
{
|
||||
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
|
||||
continue;
|
||||
}
|
||||
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
|
||||
if (tdc_iterate(thd,
|
||||
(my_hash_walk_action) close_cached_connection_tables_callback,
|
||||
&argument))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
/* Compare the connection string */
|
||||
if (connection &&
|
||||
(connection->length > share->connect_string.length ||
|
||||
(connection->length < share->connect_string.length &&
|
||||
(share->connect_string.str[connection->length] != '/' &&
|
||||
share->connect_string.str[connection->length] != '\\')) ||
|
||||
strncasecmp(connection->str, share->connect_string.str,
|
||||
connection->length)))
|
||||
continue;
|
||||
|
||||
/* close_cached_tables() only uses these elements */
|
||||
tmp.db= share->db.str;
|
||||
tmp.table_name= share->table_name.str;
|
||||
tmp.next_local= tables;
|
||||
|
||||
tables= (TABLE_LIST *) memdup_root(thd->mem_root, (char*)&tmp,
|
||||
sizeof(TABLE_LIST));
|
||||
}
|
||||
tdc_it.deinit();
|
||||
|
||||
if (tables)
|
||||
result= close_cached_tables(thd, tables, FALSE, LONG_TIMEOUT);
|
||||
|
||||
DBUG_RETURN(result);
|
||||
DBUG_RETURN(argument.tables ?
|
||||
close_cached_tables(thd, argument.tables, FALSE, LONG_TIMEOUT) :
|
||||
false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1775,7 +1818,7 @@ bool wait_while_table_is_used(THD *thd, TABLE *table,
|
|||
DBUG_ENTER("wait_while_table_is_used");
|
||||
DBUG_PRINT("enter", ("table: '%s' share: 0x%lx db_stat: %u version: %lu",
|
||||
table->s->table_name.str, (ulong) table->s,
|
||||
table->db_stat, table->s->tdc.version));
|
||||
table->db_stat, table->s->tdc->version));
|
||||
|
||||
if (thd->mdl_context.upgrade_shared_lock(
|
||||
table->mdl_ticket, MDL_EXCLUSIVE,
|
||||
|
@ -2388,10 +2431,10 @@ retry_share:
|
|||
|
||||
if (!(flags & MYSQL_OPEN_IGNORE_FLUSH))
|
||||
{
|
||||
if (share->tdc.flushed)
|
||||
if (share->tdc->flushed)
|
||||
{
|
||||
DBUG_PRINT("info", ("Found old share version: %lu current: %lu",
|
||||
share->tdc.version, tdc_refresh_version()));
|
||||
share->tdc->version, tdc_refresh_version()));
|
||||
/*
|
||||
We already have an MDL lock. But we have encountered an old
|
||||
version of table in the table definition cache which is possible
|
||||
|
@ -2422,7 +2465,7 @@ retry_share:
|
|||
goto retry_share;
|
||||
}
|
||||
|
||||
if (thd->open_tables && thd->open_tables->s->tdc.flushed)
|
||||
if (thd->open_tables && thd->open_tables->s->tdc->flushed)
|
||||
{
|
||||
/*
|
||||
If the version changes while we're opening the tables,
|
||||
|
|
|
@ -271,7 +271,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 kill_delayed_threads_for_table(TDC_element *element);
|
||||
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,
|
||||
|
|
|
@ -912,7 +912,8 @@ THD::THD(bool is_wsrep_applier)
|
|||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
wait_for_commit_ptr(0),
|
||||
main_da(0, false, false),
|
||||
m_stmt_da(&main_da)
|
||||
m_stmt_da(&main_da),
|
||||
tdc_hash_pins(0)
|
||||
#ifdef WITH_WSREP
|
||||
,
|
||||
wsrep_applier(is_wsrep_applier),
|
||||
|
@ -1701,6 +1702,8 @@ THD::~THD()
|
|||
|
||||
free_root(&main_mem_root, MYF(0));
|
||||
main_da.free_memory();
|
||||
if (tdc_hash_pins)
|
||||
lf_hash_put_pins(tdc_hash_pins);
|
||||
if (status_var.memory_used != 0)
|
||||
{
|
||||
DBUG_PRINT("error", ("memory_used: %lld", status_var.memory_used));
|
||||
|
|
|
@ -3769,6 +3769,8 @@ public:
|
|||
(rgi_slave && rgi_have_temporary_tables()));
|
||||
}
|
||||
|
||||
LF_PINS *tdc_hash_pins;
|
||||
|
||||
inline ulong wsrep_binlog_format() const
|
||||
{
|
||||
return WSREP_FORMAT(variables.binlog_format);
|
||||
|
|
|
@ -1134,7 +1134,7 @@ void mysql_ha_flush(THD *thd)
|
|||
((hash_tables->table->mdl_ticket &&
|
||||
hash_tables->table->mdl_ticket->has_pending_conflicting_lock()) ||
|
||||
(!hash_tables->table->s->tmp_table &&
|
||||
hash_tables->table->s->tdc.flushed)))
|
||||
hash_tables->table->s->tdc->flushed)))
|
||||
mysql_ha_close_table(hash_tables);
|
||||
}
|
||||
|
||||
|
|
|
@ -3048,7 +3048,7 @@ bool Delayed_insert::handle_inserts(void)
|
|||
|
||||
THD_STAGE_INFO(&thd, stage_insert);
|
||||
max_rows= delayed_insert_limit;
|
||||
if (thd.killed || table->s->tdc.flushed)
|
||||
if (thd.killed || table->s->tdc->flushed)
|
||||
{
|
||||
thd.killed= KILL_SYSTEM_THREAD;
|
||||
max_rows= ULONG_MAX; // Do as much as possible
|
||||
|
|
|
@ -76,35 +76,37 @@ print_where(COND *cond,const char *info, enum_query_type query_type)
|
|||
/* This is for debugging purposes */
|
||||
|
||||
|
||||
static my_bool print_cached_tables_callback(TDC_element *element,
|
||||
void *arg __attribute__((unused)))
|
||||
{
|
||||
TABLE *entry;
|
||||
|
||||
mysql_mutex_lock(&element->LOCK_table_share);
|
||||
TDC_element::All_share_tables_list::Iterator it(element->all_tables);
|
||||
while ((entry= it++))
|
||||
{
|
||||
THD *in_use= entry->in_use;
|
||||
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
|
||||
entry->s->db.str, entry->s->table_name.str, element->version,
|
||||
in_use ? in_use->thread_id : 0,
|
||||
entry->db_stat ? 1 : 0,
|
||||
in_use ? lock_descriptions[(int)entry->reginfo.lock_type] :
|
||||
"Not in use");
|
||||
}
|
||||
mysql_mutex_unlock(&element->LOCK_table_share);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void print_cached_tables(void)
|
||||
{
|
||||
TABLE_SHARE *share;
|
||||
TABLE *entry;
|
||||
TDC_iterator tdc_it;
|
||||
|
||||
compile_time_assert(TL_WRITE_ONLY+1 == array_elements(lock_descriptions));
|
||||
|
||||
/* purecov: begin tested */
|
||||
puts("DB Table Version Thread Open Lock");
|
||||
|
||||
tdc_it.init();
|
||||
while ((share= tdc_it.next()))
|
||||
{
|
||||
mysql_mutex_lock(&share->tdc.LOCK_table_share);
|
||||
TABLE_SHARE::All_share_tables_list::Iterator it(share->tdc.all_tables);
|
||||
while ((entry= it++))
|
||||
{
|
||||
THD *in_use= entry->in_use;
|
||||
printf("%-14.14s %-32s%6ld%8ld%6d %s\n",
|
||||
entry->s->db.str, entry->s->table_name.str, entry->s->tdc.version,
|
||||
in_use ? in_use->thread_id : 0,
|
||||
entry->db_stat ? 1 : 0,
|
||||
in_use ? lock_descriptions[(int)entry->reginfo.lock_type] :
|
||||
"Not in use");
|
||||
}
|
||||
mysql_mutex_unlock(&share->tdc.LOCK_table_share);
|
||||
}
|
||||
tdc_it.deinit();
|
||||
tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true);
|
||||
|
||||
printf("\nCurrent refresh version: %ld\n", tdc_refresh_version());
|
||||
fflush(stdout);
|
||||
/* purecov: end */
|
||||
|
|
52
sql/table.cc
52
sql/table.cc
|
@ -325,7 +325,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);
|
||||
tdc_assign_new_table_id(share);
|
||||
}
|
||||
DBUG_RETURN(share);
|
||||
}
|
||||
|
@ -422,7 +422,6 @@ void TABLE_SHARE::destroy()
|
|||
{
|
||||
mysql_mutex_destroy(&LOCK_share);
|
||||
mysql_mutex_destroy(&LOCK_ha_data);
|
||||
tdc_deinit_share(this);
|
||||
}
|
||||
my_hash_free(&name_hash);
|
||||
|
||||
|
@ -3866,11 +3865,11 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
|
|||
because we won't try to acquire tdc.LOCK_table_share while
|
||||
holding a write-lock on MDL_lock::m_rwlock.
|
||||
*/
|
||||
mysql_mutex_lock(&tdc.LOCK_table_share);
|
||||
tdc.all_tables_refs++;
|
||||
mysql_mutex_unlock(&tdc.LOCK_table_share);
|
||||
mysql_mutex_lock(&tdc->LOCK_table_share);
|
||||
tdc->all_tables_refs++;
|
||||
mysql_mutex_unlock(&tdc->LOCK_table_share);
|
||||
|
||||
All_share_tables_list::Iterator tables_it(tdc.all_tables);
|
||||
TDC_element::All_share_tables_list::Iterator tables_it(tdc->all_tables);
|
||||
|
||||
/*
|
||||
In case of multiple searches running in parallel, avoid going
|
||||
|
@ -3888,7 +3887,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
|
|||
|
||||
while ((table= tables_it++))
|
||||
{
|
||||
DBUG_ASSERT(table->in_use && tdc.flushed);
|
||||
DBUG_ASSERT(table->in_use && tdc->flushed);
|
||||
if (gvisitor->inspect_edge(&table->in_use->mdl_context))
|
||||
{
|
||||
goto end_leave_node;
|
||||
|
@ -3898,7 +3897,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush,
|
|||
tables_it.rewind();
|
||||
while ((table= tables_it++))
|
||||
{
|
||||
DBUG_ASSERT(table->in_use && tdc.flushed);
|
||||
DBUG_ASSERT(table->in_use && tdc->flushed);
|
||||
if (table->in_use->mdl_context.visit_subgraph(gvisitor))
|
||||
{
|
||||
goto end_leave_node;
|
||||
|
@ -3911,10 +3910,10 @@ end_leave_node:
|
|||
gvisitor->leave_node(src_ctx);
|
||||
|
||||
end:
|
||||
mysql_mutex_lock(&tdc.LOCK_table_share);
|
||||
if (!--tdc.all_tables_refs)
|
||||
mysql_cond_broadcast(&tdc.COND_release);
|
||||
mysql_mutex_unlock(&tdc.LOCK_table_share);
|
||||
mysql_mutex_lock(&tdc->LOCK_table_share);
|
||||
if (!--tdc->all_tables_refs)
|
||||
mysql_cond_broadcast(&tdc->COND_release);
|
||||
mysql_mutex_unlock(&tdc->LOCK_table_share);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -3949,14 +3948,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(&tdc.LOCK_table_share);
|
||||
DBUG_ASSERT(tdc.flushed);
|
||||
mysql_mutex_assert_owner(&tdc->LOCK_table_share);
|
||||
DBUG_ASSERT(tdc->flushed);
|
||||
|
||||
tdc.m_flush_tickets.push_front(&ticket);
|
||||
tdc->m_flush_tickets.push_front(&ticket);
|
||||
|
||||
mdl_context->m_wait.reset_status();
|
||||
|
||||
mysql_mutex_unlock(&tdc.LOCK_table_share);
|
||||
mysql_mutex_unlock(&tdc->LOCK_table_share);
|
||||
|
||||
mdl_context->will_wait_for(&ticket);
|
||||
|
||||
|
@ -3967,21 +3966,10 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
|
|||
|
||||
mdl_context->done_waiting_for();
|
||||
|
||||
mysql_mutex_lock(&tdc.LOCK_table_share);
|
||||
|
||||
tdc.m_flush_tickets.remove(&ticket);
|
||||
|
||||
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);
|
||||
mysql_mutex_lock(&tdc->LOCK_table_share);
|
||||
tdc->m_flush_tickets.remove(&ticket);
|
||||
mysql_cond_broadcast(&tdc->COND_release);
|
||||
mysql_mutex_unlock(&tdc->LOCK_table_share);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -4027,7 +4015,7 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime,
|
|||
|
||||
void TABLE::init(THD *thd, TABLE_LIST *tl)
|
||||
{
|
||||
DBUG_ASSERT(s->tdc.ref_count > 0 || s->tmp_table != NO_TMP_TABLE);
|
||||
DBUG_ASSERT(s->tmp_table != NO_TMP_TABLE || s->tdc->ref_count > 0);
|
||||
|
||||
if (thd->lex->need_correct_ident())
|
||||
alias_name_used= my_strcasecmp(table_alias_charset,
|
||||
|
|
28
sql/table.h
28
sql/table.h
|
@ -47,6 +47,7 @@ class ACL_internal_schema_access;
|
|||
class ACL_internal_table_access;
|
||||
class Field;
|
||||
class Table_statistics;
|
||||
class TDC_element;
|
||||
|
||||
/*
|
||||
Used to identify NESTED_JOIN structures within a join (applicable only to
|
||||
|
@ -611,32 +612,7 @@ struct TABLE_SHARE
|
|||
mysql_mutex_t LOCK_ha_data; /* To protect access to ha_data */
|
||||
mysql_mutex_t LOCK_share; /* To protect TABLE_SHARE */
|
||||
|
||||
typedef I_P_List <TABLE, TABLE_share> TABLE_list;
|
||||
typedef I_P_List <TABLE, All_share_tables> All_share_tables_list;
|
||||
struct
|
||||
{
|
||||
/**
|
||||
Protects ref_count, m_flush_tickets, all_tables, free_tables, flushed,
|
||||
all_tables_refs.
|
||||
*/
|
||||
mysql_mutex_t LOCK_table_share;
|
||||
mysql_cond_t COND_release;
|
||||
TABLE_SHARE *next, **prev; /* Link to unused shares */
|
||||
uint ref_count; /* How many TABLE objects uses this */
|
||||
uint all_tables_refs; /* Number of refs to all_tables */
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
All_share_tables_list all_tables;
|
||||
TABLE_list free_tables;
|
||||
ulong version;
|
||||
bool flushed;
|
||||
} tdc;
|
||||
TDC_element *tdc;
|
||||
|
||||
LEX_CUSTRING tabledef_version;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -16,6 +16,165 @@
|
|||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
|
||||
extern PSI_mutex_key key_TABLE_SHARE_LOCK_table_share;
|
||||
extern PSI_cond_key key_TABLE_SHARE_COND_release;
|
||||
|
||||
class TDC_element
|
||||
{
|
||||
public:
|
||||
uchar m_key[NAME_LEN + 1 + NAME_LEN + 1];
|
||||
uint m_key_length;
|
||||
ulong version;
|
||||
bool flushed;
|
||||
TABLE_SHARE *share;
|
||||
|
||||
typedef I_P_List <TABLE, TABLE_share> TABLE_list;
|
||||
typedef I_P_List <TABLE, All_share_tables> All_share_tables_list;
|
||||
/**
|
||||
Protects ref_count, m_flush_tickets, all_tables, free_tables, flushed,
|
||||
all_tables_refs.
|
||||
*/
|
||||
mysql_mutex_t LOCK_table_share;
|
||||
mysql_cond_t COND_release;
|
||||
TDC_element *next, **prev; /* Link to unused shares */
|
||||
uint ref_count; /* How many TABLE objects uses this */
|
||||
uint all_tables_refs; /* Number of refs to all_tables */
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
All_share_tables_list all_tables;
|
||||
TABLE_list free_tables;
|
||||
|
||||
TDC_element() {}
|
||||
|
||||
TDC_element(const char *key, uint key_length) : m_key_length(key_length)
|
||||
{
|
||||
memcpy(m_key, key, key_length);
|
||||
}
|
||||
|
||||
|
||||
void assert_clean_share()
|
||||
{
|
||||
DBUG_ASSERT(share == 0);
|
||||
DBUG_ASSERT(ref_count == 0);
|
||||
DBUG_ASSERT(m_flush_tickets.is_empty());
|
||||
DBUG_ASSERT(all_tables.is_empty());
|
||||
DBUG_ASSERT(free_tables.is_empty());
|
||||
DBUG_ASSERT(all_tables_refs == 0);
|
||||
DBUG_ASSERT(next == 0);
|
||||
DBUG_ASSERT(prev == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Acquire TABLE object from table cache.
|
||||
|
||||
@pre share must be protected against removal.
|
||||
|
||||
Acquired object cannot be evicted or acquired again.
|
||||
|
||||
@return TABLE object, or NULL if no unused objects.
|
||||
*/
|
||||
|
||||
TABLE *acquire_table(THD *thd)
|
||||
{
|
||||
TABLE *table;
|
||||
|
||||
mysql_mutex_lock(&LOCK_table_share);
|
||||
table= free_tables.pop_front();
|
||||
if (table)
|
||||
{
|
||||
DBUG_ASSERT(!table->in_use);
|
||||
table->in_use= thd;
|
||||
/* The ex-unused table must be fully functional. */
|
||||
DBUG_ASSERT(table->db_stat && table->file);
|
||||
/* The children must be detached from the table. */
|
||||
DBUG_ASSERT(!table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN));
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_table_share);
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get last element of free_tables.
|
||||
*/
|
||||
|
||||
TABLE *free_tables_back()
|
||||
{
|
||||
TABLE_list::Iterator it(share->tdc->free_tables);
|
||||
TABLE *entry, *last= 0;
|
||||
while ((entry= it++))
|
||||
last= entry;
|
||||
return last;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Wait for MDL deadlock detector to complete traversing tdc.all_tables.
|
||||
|
||||
Must be called before updating TABLE_SHARE::tdc.all_tables.
|
||||
*/
|
||||
|
||||
void wait_for_mdl_deadlock_detector()
|
||||
{
|
||||
while (all_tables_refs)
|
||||
mysql_cond_wait(&COND_release, &LOCK_table_share);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prepeare table share for use with table definition cache.
|
||||
*/
|
||||
|
||||
static void lf_alloc_constructor(uchar *arg)
|
||||
{
|
||||
TDC_element *element= (TDC_element*) (arg + LF_HASH_OVERHEAD);
|
||||
DBUG_ENTER("lf_alloc_constructor");
|
||||
mysql_mutex_init(key_TABLE_SHARE_LOCK_table_share,
|
||||
&element->LOCK_table_share, MY_MUTEX_INIT_FAST);
|
||||
mysql_cond_init(key_TABLE_SHARE_COND_release, &element->COND_release, 0);
|
||||
element->m_flush_tickets.empty();
|
||||
element->all_tables.empty();
|
||||
element->free_tables.empty();
|
||||
element->all_tables_refs= 0;
|
||||
element->share= 0;
|
||||
element->ref_count= 0;
|
||||
element->next= 0;
|
||||
element->prev= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Release table definition cache specific resources of table share.
|
||||
*/
|
||||
|
||||
static void lf_alloc_destructor(uchar *arg)
|
||||
{
|
||||
TDC_element *element= (TDC_element*) (arg + LF_HASH_OVERHEAD);
|
||||
DBUG_ENTER("lf_alloc_destructor");
|
||||
element->assert_clean_share();
|
||||
mysql_cond_destroy(&element->COND_release);
|
||||
mysql_mutex_destroy(&element->LOCK_table_share);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
static uchar *key(const TDC_element *element, size_t *length,
|
||||
my_bool not_used __attribute__((unused)))
|
||||
{
|
||||
*length= element->m_key_length;
|
||||
return (uchar*) element->m_key;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
enum enum_tdc_remove_table_type
|
||||
{
|
||||
TDC_RT_REMOVE_ALL,
|
||||
|
@ -27,15 +186,14 @@ enum enum_tdc_remove_table_type
|
|||
extern ulong tdc_size;
|
||||
extern ulong tc_size;
|
||||
|
||||
extern int tdc_init(void);
|
||||
extern void 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 TDC_element *tdc_lock_share(THD *thd, const char *db,
|
||||
const char *table_name);
|
||||
extern void tdc_unlock_share(TDC_element *element);
|
||||
extern TABLE_SHARE *tdc_acquire_share(THD *thd, const char *db,
|
||||
const char *table_name,
|
||||
const char *key, uint key_length,
|
||||
|
@ -52,6 +210,8 @@ extern int tdc_wait_for_old_version(THD *thd, const char *db,
|
|||
extern ulong tdc_refresh_version(void);
|
||||
extern ulong tdc_increment_refresh_version(void);
|
||||
extern void tdc_assign_new_table_id(TABLE_SHARE *share);
|
||||
extern int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument,
|
||||
bool no_dups= false);
|
||||
|
||||
extern uint tc_records(void);
|
||||
extern void tc_purge(bool mark_flushed= false);
|
||||
|
@ -125,13 +285,3 @@ static inline TABLE_SHARE *tdc_acquire_share_shortlived(THD *thd, TABLE_LIST *tl
|
|||
return tdc_acquire_share(thd, tl->db, tl->table_name, key, key_length,
|
||||
tl->mdl_request.key.tc_hash_value(), flags, 0);
|
||||
}
|
||||
|
||||
|
||||
class TDC_iterator
|
||||
{
|
||||
ulong idx;
|
||||
public:
|
||||
void init(void);
|
||||
void deinit(void);
|
||||
TABLE_SHARE *next(void);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue