mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
bug#3565 - HANDLER and FLUSH TABLE/TABLES deadlock.
Redesigned the handler close functions so that they are usable at different places where waiting for closing tables is done.
This commit is contained in:
120
mysql-test/r/flush_table.result
Normal file
120
mysql-test/r/flush_table.result
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
drop table if exists t1;
|
||||||
|
create table t1 (a int not null auto_increment primary key);
|
||||||
|
insert into t1 values(0);
|
||||||
|
lock table t1 read;
|
||||||
|
flush table t1;
|
||||||
|
check table t1;
|
||||||
|
Table Op Msg_type Msg_text
|
||||||
|
test.t1 check status OK
|
||||||
|
drop table t1;
|
||||||
|
drop database if exists test_test;
|
||||||
|
create database test_test;
|
||||||
|
use test_test;
|
||||||
|
create table t1(table_id char(20) primary key);
|
||||||
|
insert into t1 values ('test_test.t1');
|
||||||
|
insert into t1 values ('');
|
||||||
|
handler t1 open;
|
||||||
|
handler t1 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test_test.t1
|
||||||
|
|
||||||
|
create table t2(table_id char(20) primary key);
|
||||||
|
insert into t2 values ('test_test.t2');
|
||||||
|
insert into t2 values ('');
|
||||||
|
handler t2 open;
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test_test.t2
|
||||||
|
|
||||||
|
use test;
|
||||||
|
drop table if exists t1;
|
||||||
|
create table t1(table_id char(20) primary key);
|
||||||
|
insert into t1 values ('test.t1');
|
||||||
|
insert into t1 values ('');
|
||||||
|
handler t1 open;
|
||||||
|
handler t1 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t1
|
||||||
|
|
||||||
|
use test;
|
||||||
|
handler test.t1 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t1
|
||||||
|
|
||||||
|
handler test.t2 read first limit 9;
|
||||||
|
Unknown table 't2' in HANDLER
|
||||||
|
handler test_test.t1 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test_test.t1
|
||||||
|
|
||||||
|
handler test_test.t2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test_test.t2
|
||||||
|
|
||||||
|
handler test_test.t1 close;
|
||||||
|
drop table test_test.t1;
|
||||||
|
handler test_test.t2 close;
|
||||||
|
drop table test_test.t2;
|
||||||
|
drop database test_test;
|
||||||
|
use test;
|
||||||
|
handler test.t1 close;
|
||||||
|
drop table test.t1;
|
||||||
|
drop table if exists t1;
|
||||||
|
drop table if exists t2;
|
||||||
|
create table t1(table_id char(20) primary key);
|
||||||
|
create table t2(table_id char(20) primary key);
|
||||||
|
insert into t1 values ('test.t1');
|
||||||
|
insert into t1 values ('');
|
||||||
|
insert into t2 values ('test.t2');
|
||||||
|
insert into t2 values ('');
|
||||||
|
handler t1 open as a1;
|
||||||
|
handler t1 open as a2;
|
||||||
|
handler t2 open;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t1
|
||||||
|
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t1
|
||||||
|
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t2
|
||||||
|
|
||||||
|
flush tables;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
Unknown table 'a1' in HANDLER
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
Unknown table 'a2' in HANDLER
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
Unknown table 't2' in HANDLER
|
||||||
|
handler t1 open as a1;
|
||||||
|
handler t1 open as a2;
|
||||||
|
handler t2 open;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t1
|
||||||
|
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t1
|
||||||
|
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t2
|
||||||
|
|
||||||
|
flush table t1;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
Unknown table 'a1' in HANDLER
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
Unknown table 'a2' in HANDLER
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
table_id
|
||||||
|
test.t2
|
||||||
|
|
||||||
|
flush table t2;
|
||||||
|
handler t2 close;
|
||||||
|
Unknown table 't2' in HANDLER
|
||||||
|
drop table t1;
|
||||||
|
drop table t2;
|
@ -4,10 +4,111 @@
|
|||||||
# Test of flush table
|
# Test of flush table
|
||||||
#
|
#
|
||||||
|
|
||||||
#drop table if exists t1;
|
drop table if exists t1;
|
||||||
#create table t1 (a int not null auto_increment primary key);
|
create table t1 (a int not null auto_increment primary key);
|
||||||
#insert into t1 values(0);
|
insert into t1 values(0);
|
||||||
#lock table t1 read;
|
lock table t1 read;
|
||||||
#flush table t1;
|
flush table t1;
|
||||||
#check table t1;
|
check table t1;
|
||||||
#drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check if two database names beginning the same are seen as different.
|
||||||
|
#
|
||||||
|
# This database begins like the usual 'test' database.
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists test_test;
|
||||||
|
--enable_warnings
|
||||||
|
create database test_test;
|
||||||
|
use test_test;
|
||||||
|
create table t1(table_id char(20) primary key);
|
||||||
|
insert into t1 values ('test_test.t1');
|
||||||
|
insert into t1 values ('');
|
||||||
|
handler t1 open;
|
||||||
|
handler t1 read first limit 9;
|
||||||
|
create table t2(table_id char(20) primary key);
|
||||||
|
insert into t2 values ('test_test.t2');
|
||||||
|
insert into t2 values ('');
|
||||||
|
handler t2 open;
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
#
|
||||||
|
# This is the usual 'test' database.
|
||||||
|
#
|
||||||
|
use test;
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1;
|
||||||
|
--enable_warnings
|
||||||
|
create table t1(table_id char(20) primary key);
|
||||||
|
insert into t1 values ('test.t1');
|
||||||
|
insert into t1 values ('');
|
||||||
|
handler t1 open;
|
||||||
|
handler t1 read first limit 9;
|
||||||
|
#
|
||||||
|
# Check accesibility of all the tables.
|
||||||
|
#
|
||||||
|
use test;
|
||||||
|
handler test.t1 read first limit 9;
|
||||||
|
--error 1109;
|
||||||
|
handler test.t2 read first limit 9;
|
||||||
|
handler test_test.t1 read first limit 9;
|
||||||
|
handler test_test.t2 read first limit 9;
|
||||||
|
#
|
||||||
|
# Cleanup.
|
||||||
|
#
|
||||||
|
handler test_test.t1 close;
|
||||||
|
drop table test_test.t1;
|
||||||
|
handler test_test.t2 close;
|
||||||
|
drop table test_test.t2;
|
||||||
|
drop database test_test;
|
||||||
|
#
|
||||||
|
use test;
|
||||||
|
handler test.t1 close;
|
||||||
|
drop table test.t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# In the following test FLUSH TABLES produces a deadlock
|
||||||
|
# (hang forever) if the fix for bug#3565 is missing.
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1;
|
||||||
|
drop table if exists t2;
|
||||||
|
--enable_warnings
|
||||||
|
create table t1(table_id char(20) primary key);
|
||||||
|
create table t2(table_id char(20) primary key);
|
||||||
|
insert into t1 values ('test.t1');
|
||||||
|
insert into t1 values ('');
|
||||||
|
insert into t2 values ('test.t2');
|
||||||
|
insert into t2 values ('');
|
||||||
|
handler t1 open as a1;
|
||||||
|
handler t1 open as a2;
|
||||||
|
handler t2 open;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
flush tables;
|
||||||
|
--error 1109;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
--error 1109;
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
--error 1109;
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
#
|
||||||
|
handler t1 open as a1;
|
||||||
|
handler t1 open as a2;
|
||||||
|
handler t2 open;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
flush table t1;
|
||||||
|
--error 1109;
|
||||||
|
handler a1 read first limit 9;
|
||||||
|
--error 1109;
|
||||||
|
handler a2 read first limit 9;
|
||||||
|
handler t2 read first limit 9;
|
||||||
|
flush table t2;
|
||||||
|
--error 1109;
|
||||||
|
handler t2 close;
|
||||||
|
drop table t1;
|
||||||
|
drop table t2;
|
||||||
|
|
||||||
|
@ -538,8 +538,9 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
|
|||||||
|
|
||||||
/* sql_handler.cc */
|
/* sql_handler.cc */
|
||||||
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
|
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
|
||||||
int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok=0);
|
int mysql_ha_close(THD *thd, TABLE_LIST *tables,
|
||||||
int mysql_ha_closeall(THD *thd, TABLE_LIST *tables);
|
bool dont_send_ok=0, bool dont_lock=0, bool no_alias=0);
|
||||||
|
int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed=0);
|
||||||
int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
|
int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
|
||||||
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
|
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
|
||||||
|
|
||||||
@ -587,7 +588,6 @@ void free_io_cache(TABLE *entry);
|
|||||||
void intern_close_table(TABLE *entry);
|
void intern_close_table(TABLE *entry);
|
||||||
bool close_thread_table(THD *thd, TABLE **table_ptr);
|
bool close_thread_table(THD *thd, TABLE **table_ptr);
|
||||||
void close_thread_tables(THD *thd,bool locked=0);
|
void close_thread_tables(THD *thd,bool locked=0);
|
||||||
bool close_thread_table(THD *thd, TABLE **table_ptr);
|
|
||||||
void close_temporary_tables(THD *thd);
|
void close_temporary_tables(THD *thd);
|
||||||
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
|
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||||
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
|
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
|
||||||
|
@ -389,6 +389,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
|
|||||||
thd->proc_info="Flushing tables";
|
thd->proc_info="Flushing tables";
|
||||||
|
|
||||||
close_old_data_files(thd,thd->open_tables,1,1);
|
close_old_data_files(thd,thd->open_tables,1,1);
|
||||||
|
mysql_ha_close_list(thd, tables);
|
||||||
bool found=1;
|
bool found=1;
|
||||||
/* Wait until all threads has closed all the tables we had locked */
|
/* Wait until all threads has closed all the tables we had locked */
|
||||||
DBUG_PRINT("info", ("Waiting for others threads to close their open tables"));
|
DBUG_PRINT("info", ("Waiting for others threads to close their open tables"));
|
||||||
@ -857,6 +858,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* close handler tables which are marked for flush */
|
||||||
|
mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1);
|
||||||
|
|
||||||
for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
|
for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ;
|
||||||
table && table->in_use ;
|
table && table->in_use ;
|
||||||
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
|
table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length))
|
||||||
@ -1222,6 +1226,7 @@ bool wait_for_tables(THD *thd)
|
|||||||
{
|
{
|
||||||
thd->some_tables_deleted=0;
|
thd->some_tables_deleted=0;
|
||||||
close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0);
|
close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0);
|
||||||
|
mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1);
|
||||||
if (!table_is_used(thd->open_tables,1))
|
if (!table_is_used(thd->open_tables,1))
|
||||||
break;
|
break;
|
||||||
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
|
(void) pthread_cond_wait(&COND_refresh,&LOCK_open);
|
||||||
|
@ -44,7 +44,9 @@
|
|||||||
thd->handler_tables=tmp; }
|
thd->handler_tables=tmp; }
|
||||||
|
|
||||||
static TABLE **find_table_ptr_by_name(THD *thd,const char *db,
|
static TABLE **find_table_ptr_by_name(THD *thd,const char *db,
|
||||||
const char *table_name, bool is_alias);
|
const char *table_name,
|
||||||
|
bool is_alias, bool dont_lock,
|
||||||
|
bool *was_flushed);
|
||||||
|
|
||||||
int mysql_ha_open(THD *thd, TABLE_LIST *tables)
|
int mysql_ha_open(THD *thd, TABLE_LIST *tables)
|
||||||
{
|
{
|
||||||
@ -66,23 +68,59 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
|
|
||||||
{
|
|
||||||
TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->alias, 1);
|
|
||||||
|
|
||||||
if (*ptr)
|
/*
|
||||||
|
Close a HANDLER table.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_ha_close()
|
||||||
|
thd Thread identifier.
|
||||||
|
tables A list of tables with the first entry to close.
|
||||||
|
dont_send_ok Suppresses the commands' ok message and
|
||||||
|
error message and error return.
|
||||||
|
dont_lock Suppresses the normal locking of LOCK_open.
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Though this function takes a list of tables, only the first list entry
|
||||||
|
will be closed. Broadcasts a COND_refresh condition.
|
||||||
|
If mysql_ha_close() is not called from the parser, 'dont_send_ok'
|
||||||
|
must be set.
|
||||||
|
If the caller did already lock LOCK_open, it must set 'dont_lock'.
|
||||||
|
|
||||||
|
IMPLEMENTATION
|
||||||
|
find_table_ptr_by_name() closes the table, if a FLUSH TABLE is outstanding.
|
||||||
|
It returns a NULL pointer in this case, but flags the situation in
|
||||||
|
'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages
|
||||||
|
is suppressed.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 ok
|
||||||
|
-1 error
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysql_ha_close(THD *thd, TABLE_LIST *tables,
|
||||||
|
bool dont_send_ok, bool dont_lock, bool no_alias)
|
||||||
|
{
|
||||||
|
TABLE **table_ptr;
|
||||||
|
bool was_flushed;
|
||||||
|
|
||||||
|
table_ptr= find_table_ptr_by_name(thd, tables->db, tables->alias,
|
||||||
|
!no_alias, dont_lock, &was_flushed);
|
||||||
|
if (*table_ptr)
|
||||||
{
|
{
|
||||||
|
if (!dont_lock)
|
||||||
VOID(pthread_mutex_lock(&LOCK_open));
|
VOID(pthread_mutex_lock(&LOCK_open));
|
||||||
if (close_thread_table(thd, ptr))
|
if (close_thread_table(thd, table_ptr))
|
||||||
{
|
{
|
||||||
/* Tell threads waiting for refresh that something has happened */
|
/* Tell threads waiting for refresh that something has happened */
|
||||||
VOID(pthread_cond_broadcast(&COND_refresh));
|
VOID(pthread_cond_broadcast(&COND_refresh));
|
||||||
}
|
}
|
||||||
|
if (!dont_lock)
|
||||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||||
}
|
}
|
||||||
else
|
else if (!was_flushed && !dont_send_ok)
|
||||||
{
|
{
|
||||||
my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
|
my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
|
||||||
tables->alias, "HANDLER");
|
tables->alias, "HANDLER");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -91,14 +129,65 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mysql_ha_closeall(THD *thd, TABLE_LIST *tables)
|
|
||||||
|
/*
|
||||||
|
Close a list of HANDLER tables.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_ha_close_list()
|
||||||
|
thd Thread identifier.
|
||||||
|
tables The list of tables to close. If NULL,
|
||||||
|
close all HANDLER tables.
|
||||||
|
flushed Close only tables which are marked flushed.
|
||||||
|
Used only if tables is NULL.
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The list of HANDLER tables may be NULL, in which case all HANDLER
|
||||||
|
tables are closed. Broadcasts a COND_refresh condition, for
|
||||||
|
every table closed. If 'tables' is NULL and 'flushed' is set,
|
||||||
|
all HANDLER tables marked for flush are closed.
|
||||||
|
The caller must lock LOCK_open.
|
||||||
|
|
||||||
|
IMPLEMENTATION
|
||||||
|
find_table_ptr_by_name() closes the table, if it is marked for flush.
|
||||||
|
It returns a NULL pointer in this case, but flags the situation in
|
||||||
|
'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages
|
||||||
|
is suppressed.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 ok
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed)
|
||||||
{
|
{
|
||||||
TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0);
|
TABLE_LIST *tl_item;
|
||||||
if (*ptr && close_thread_table(thd, ptr))
|
TABLE **table_ptr;
|
||||||
|
|
||||||
|
if (tables)
|
||||||
|
{
|
||||||
|
for (tl_item= tables ; tl_item; tl_item= tl_item->next)
|
||||||
|
{
|
||||||
|
mysql_ha_close(thd, tl_item, /*dont_send_ok*/ 1,
|
||||||
|
/*dont_lock*/ 1, /*no_alias*/ 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
table_ptr= &(thd->handler_tables);
|
||||||
|
while (*table_ptr)
|
||||||
|
{
|
||||||
|
if (! flushed || ((*table_ptr)->version != refresh_version))
|
||||||
|
{
|
||||||
|
if (close_thread_table(thd, table_ptr))
|
||||||
{
|
{
|
||||||
/* Tell threads waiting for refresh that something has happened */
|
/* Tell threads waiting for refresh that something has happened */
|
||||||
VOID(pthread_cond_broadcast(&COND_refresh));
|
VOID(pthread_cond_broadcast(&COND_refresh));
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
table_ptr= &((*table_ptr)->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +201,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
|||||||
ha_rows select_limit,ha_rows offset_limit)
|
ha_rows select_limit,ha_rows offset_limit)
|
||||||
{
|
{
|
||||||
int err, keyno=-1;
|
int err, keyno=-1;
|
||||||
TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->alias, 1);
|
bool was_flushed;
|
||||||
|
TABLE *table= *find_table_ptr_by_name(thd, tables->db, tables->alias,
|
||||||
|
/*is_alias*/ 1, /*dont_lock*/ 0,
|
||||||
|
&was_flushed);
|
||||||
if (!table)
|
if (!table)
|
||||||
{
|
{
|
||||||
my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
|
my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
|
||||||
@ -278,36 +370,76 @@ err0:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find a HANDLER table by name.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
find_table_ptr_by_name()
|
||||||
|
thd Thread identifier.
|
||||||
|
db Database (schema) name.
|
||||||
|
table_name Table name ;-).
|
||||||
|
is_alias Table name may be an alias name.
|
||||||
|
dont_lock Suppresses the normal locking of LOCK_open.
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Find the table 'db'.'table_name' in the list of HANDLER tables of the
|
||||||
|
thread 'thd'. If the table has been marked by FLUSH TABLE(S), close it,
|
||||||
|
flag this situation in '*was_flushed' and broadcast a COND_refresh
|
||||||
|
condition.
|
||||||
|
An empty database (schema) name matches all database (schema) names.
|
||||||
|
If the caller did already lock LOCK_open, it must set 'dont_lock'.
|
||||||
|
|
||||||
|
IMPLEMENTATION
|
||||||
|
Just in case that the table is twice in 'thd->handler_tables' (!?!),
|
||||||
|
the loop does not break when the table was flushed. If another table
|
||||||
|
by that name was found and not flushed, '*was_flushed' is cleared again,
|
||||||
|
since a pointer to an open HANDLER table is returned.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
*was_flushed Table has been closed due to FLUSH TABLE.
|
||||||
|
NULL A HANDLER Table by that name does not exist (any more).
|
||||||
|
!= NULL Pointer to the TABLE structure.
|
||||||
|
*/
|
||||||
|
|
||||||
static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
|
static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
|
||||||
const char *table_name, bool is_alias)
|
const char *table_name,
|
||||||
|
bool is_alias, bool dont_lock,
|
||||||
|
bool *was_flushed)
|
||||||
{
|
{
|
||||||
int dblen;
|
int dblen;
|
||||||
TABLE **ptr;
|
TABLE **table_ptr;
|
||||||
|
|
||||||
DBUG_ASSERT(db);
|
DBUG_ASSERT(db);
|
||||||
dblen=*db ? strlen(db)+1 : 0;
|
dblen= *db ? strlen(db)+1 : 0;
|
||||||
ptr=&(thd->handler_tables);
|
table_ptr= &(thd->handler_tables);
|
||||||
|
*was_flushed= FALSE;
|
||||||
|
|
||||||
for (TABLE *table=*ptr; table ; table=*ptr)
|
for (TABLE *table=*table_ptr; table ; table=*table_ptr)
|
||||||
{
|
{
|
||||||
if ((!dblen || !memcmp(table->table_cache_key, db, dblen)) &&
|
if ((!dblen || !memcmp(table->table_cache_key, db, dblen)) &&
|
||||||
!my_strcasecmp((is_alias ? table->table_name : table->real_name),table_name))
|
!my_strcasecmp((is_alias ? table->table_name : table->real_name),
|
||||||
|
table_name))
|
||||||
{
|
{
|
||||||
if (table->version != refresh_version)
|
if (table->version != refresh_version)
|
||||||
{
|
{
|
||||||
|
if (!dont_lock)
|
||||||
VOID(pthread_mutex_lock(&LOCK_open));
|
VOID(pthread_mutex_lock(&LOCK_open));
|
||||||
if (close_thread_table(thd, ptr))
|
if (close_thread_table(thd, table_ptr))
|
||||||
{
|
{
|
||||||
/* Tell threads waiting for refresh that something has happened */
|
/* Tell threads waiting for refresh that something has happened */
|
||||||
VOID(pthread_cond_broadcast(&COND_refresh));
|
VOID(pthread_cond_broadcast(&COND_refresh));
|
||||||
}
|
}
|
||||||
|
if (!dont_lock)
|
||||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||||
|
*was_flushed= TRUE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
*was_flushed= FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ptr=&(table->next);
|
table_ptr=&(table->next);
|
||||||
}
|
}
|
||||||
return ptr;
|
return table_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
|||||||
for (table=tables ; table ; table=table->next)
|
for (table=tables ; table ; table=table->next)
|
||||||
{
|
{
|
||||||
char *db=table->db;
|
char *db=table->db;
|
||||||
mysql_ha_closeall(thd, table);
|
mysql_ha_close(thd, table, /*dont_send_ok*/ 1, /*dont_lock*/ 1);
|
||||||
if (!close_temporary_table(thd, db, table->real_name))
|
if (!close_temporary_table(thd, db, table->real_name))
|
||||||
{
|
{
|
||||||
tmp_table_deleted=1;
|
tmp_table_deleted=1;
|
||||||
@ -1230,7 +1230,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
|||||||
if (send_fields(thd, field_list, 1))
|
if (send_fields(thd, field_list, 1))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
mysql_ha_closeall(thd, tables);
|
mysql_ha_close(thd, tables, /*dont_send_ok*/ 1, /*dont_lock*/ 1);
|
||||||
for (table = tables; table; table = table->next)
|
for (table = tables; table; table = table->next)
|
||||||
{
|
{
|
||||||
char table_name[NAME_LEN*2+2];
|
char table_name[NAME_LEN*2+2];
|
||||||
@ -1492,7 +1492,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
|||||||
}
|
}
|
||||||
used_fields=create_info->used_fields;
|
used_fields=create_info->used_fields;
|
||||||
|
|
||||||
mysql_ha_closeall(thd, table_list);
|
mysql_ha_close(thd, table_list, /*dont_send_ok*/ 1, /*dont_lock*/ 1);
|
||||||
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
|
if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ)))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user