Skip to content

Commit 40088bf

Browse files
committed
MDEV-13407 innodb.drop_table_background failed in buildbot with "Tablespace for table exists"
The InnoDB background DROP TABLE queue is something that we should really remove, but are unable to until we remove dict_operation_lock so that DDL and DML operations can be combined in a single transaction. Because the queue is not persistent, it is not crash-safe. In stable versions of MariaDB, we can only try harder to drop all enqueued tables before server shutdown. row_mysql_drop_t::table_id: Replaces table_name. row_drop_tables_for_mysql_in_background(): Do not remove the entry from the list as long as the table exists. In this way, the table should eventually be dropped.
1 parent 03e91ce commit 40088bf

File tree

2 files changed

+74
-198
lines changed

2 files changed

+74
-198
lines changed

storage/innobase/row/row0mysql.cc

Lines changed: 37 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
7373

7474
/** Chain node of the list of tables to drop in the background. */
7575
struct row_mysql_drop_t{
76-
char* table_name; /*!< table name */
76+
table_id_t table_id; /*!< table id */
7777
UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
7878
/*!< list chain node */
7979
};
@@ -136,19 +136,6 @@ row_mysql_is_system_table(
136136
|| 0 == strcmp(name + 6, "db"));
137137
}
138138

139-
/*********************************************************************//**
140-
If a table is not yet in the drop list, adds the table to the list of tables
141-
which the master thread drops in background. We need this on Unix because in
142-
ALTER TABLE MySQL may call drop table even if the table has running queries on
143-
it. Also, if there are running foreign key checks on the table, we drop the
144-
table lazily.
145-
@return TRUE if the table was not yet in the drop list, and was added there */
146-
static
147-
ibool
148-
row_add_table_to_background_drop_list(
149-
/*==================================*/
150-
const char* name); /*!< in: table name */
151-
152139
/*******************************************************************//**
153140
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
154141
static
@@ -2727,7 +2714,7 @@ row_drop_tables_for_mysql_in_background(void)
27272714
mutex_enter(&row_drop_list_mutex);
27282715

27292716
ut_a(row_mysql_drop_list_inited);
2730-
2717+
next:
27312718
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
27322719

27332720
n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
@@ -2740,62 +2727,39 @@ row_drop_tables_for_mysql_in_background(void)
27402727
return(n_tables + n_tables_dropped);
27412728
}
27422729

2743-
DBUG_EXECUTE_IF("row_drop_tables_in_background_sleep",
2744-
os_thread_sleep(5000000);
2745-
);
2746-
2747-
table = dict_table_open_on_name(drop->table_name, FALSE, FALSE,
2748-
DICT_ERR_IGNORE_NONE);
2749-
2750-
if (table == NULL) {
2751-
/* If for some reason the table has already been dropped
2752-
through some other mechanism, do not try to drop it */
2730+
table = dict_table_open_on_id(drop->table_id, FALSE,
2731+
DICT_TABLE_OP_NORMAL);
27532732

2754-
goto already_dropped;
2733+
if (!table) {
2734+
n_tables_dropped++;
2735+
mutex_enter(&row_drop_list_mutex);
2736+
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2737+
MONITOR_DEC(MONITOR_BACKGROUND_DROP_TABLE);
2738+
ut_free(drop);
2739+
goto next;
27552740
}
27562741

2742+
ut_a(!table->can_be_evicted);
2743+
27572744
if (!table->to_be_dropped) {
2758-
/* There is a scenario: the old table is dropped
2759-
just after it's added into drop list, and new
2760-
table with the same name is created, then we try
2761-
to drop the new table in background. */
27622745
dict_table_close(table, FALSE, FALSE);
27632746

2764-
goto already_dropped;
2747+
mutex_enter(&row_drop_list_mutex);
2748+
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2749+
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list,
2750+
drop);
2751+
goto next;
27652752
}
27662753

2767-
ut_a(!table->can_be_evicted);
2768-
27692754
dict_table_close(table, FALSE, FALSE);
27702755

27712756
if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2772-
drop->table_name)) {
2757+
table->name)) {
27732758
/* If the DROP fails for some table, we return, and let the
27742759
main thread retry later */
2775-
27762760
return(n_tables + n_tables_dropped);
27772761
}
27782762

2779-
n_tables_dropped++;
2780-
2781-
already_dropped:
2782-
mutex_enter(&row_drop_list_mutex);
2783-
2784-
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2785-
2786-
MONITOR_DEC(MONITOR_BACKGROUND_DROP_TABLE);
2787-
2788-
ut_print_timestamp(stderr);
2789-
fputs(" InnoDB: Dropped table ", stderr);
2790-
ut_print_name(stderr, NULL, TRUE, drop->table_name);
2791-
fputs(" in background drop queue.\n", stderr);
2792-
2793-
mem_free(drop->table_name);
2794-
2795-
mem_free(drop);
2796-
2797-
mutex_exit(&row_drop_list_mutex);
2798-
27992763
goto loop;
28002764
}
28012765

@@ -2827,14 +2791,13 @@ which the master thread drops in background. We need this on Unix because in
28272791
ALTER TABLE MySQL may call drop table even if the table has running queries on
28282792
it. Also, if there are running foreign key checks on the table, we drop the
28292793
table lazily.
2830-
@return TRUE if the table was not yet in the drop list, and was added there */
2794+
@return whether background DROP TABLE was scheduled for the first time */
28312795
static
2832-
ibool
2833-
row_add_table_to_background_drop_list(
2834-
/*==================================*/
2835-
const char* name) /*!< in: table name */
2796+
bool
2797+
row_add_table_to_background_drop_list(table_id_t table_id)
28362798
{
28372799
row_mysql_drop_t* drop;
2800+
bool added = true;
28382801

28392802
mutex_enter(&row_drop_list_mutex);
28402803

@@ -2845,31 +2808,21 @@ row_add_table_to_background_drop_list(
28452808
drop != NULL;
28462809
drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop)) {
28472810

2848-
if (strcmp(drop->table_name, name) == 0) {
2849-
/* Already in the list */
2850-
2851-
mutex_exit(&row_drop_list_mutex);
2852-
2853-
return(FALSE);
2811+
if (drop->table_id == table_id) {
2812+
added = false;
2813+
goto func_exit;
28542814
}
28552815
}
28562816

2857-
drop = static_cast<row_mysql_drop_t*>(
2858-
mem_alloc(sizeof(row_mysql_drop_t)));
2859-
2860-
drop->table_name = mem_strdup(name);
2817+
drop = static_cast<row_mysql_drop_t*>(ut_malloc(sizeof *drop));
2818+
drop->table_id = table_id;
28612819

28622820
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
28632821

28642822
MONITOR_INC(MONITOR_BACKGROUND_DROP_TABLE);
2865-
2866-
/* fputs("InnoDB: Adding table ", stderr);
2867-
ut_print_name(stderr, trx, TRUE, drop->table_name);
2868-
fputs(" to background drop list\n", stderr); */
2869-
2823+
func_exit:
28702824
mutex_exit(&row_drop_list_mutex);
2871-
2872-
return(TRUE);
2825+
return added;
28732826
}
28742827

28752828
/*********************************************************************//**
@@ -4043,7 +3996,7 @@ row_drop_table_for_mysql(
40433996

40443997

40453998
DBUG_EXECUTE_IF("row_drop_table_add_to_background",
4046-
row_add_table_to_background_drop_list(table->name);
3999+
row_add_table_to_background_drop_list(table->id);
40474000
err = DB_SUCCESS;
40484001
goto funct_exit;
40494002
);
@@ -4055,33 +4008,22 @@ row_drop_table_for_mysql(
40554008
checks take an IS or IX lock on the table. */
40564009

40574010
if (table->n_foreign_key_checks_running > 0) {
4058-
4059-
const char* save_tablename = table->name;
4060-
ibool added;
4061-
4062-
added = row_add_table_to_background_drop_list(save_tablename);
4063-
4064-
if (added) {
4011+
if (row_add_table_to_background_drop_list(table->id)) {
40654012
ut_print_timestamp(stderr);
40664013
fputs(" InnoDB: You are trying to drop table ",
40674014
stderr);
4068-
ut_print_name(stderr, trx, TRUE, save_tablename);
4015+
ut_print_name(stderr, trx, TRUE, table->name);
40694016
fputs("\n"
40704017
"InnoDB: though there is a"
40714018
" foreign key check running on it.\n"
40724019
"InnoDB: Adding the table to"
40734020
" the background drop queue.\n",
40744021
stderr);
4075-
4076-
/* We return DB_SUCCESS to MySQL though the drop will
4077-
happen lazily later */
4078-
4079-
err = DB_SUCCESS;
4080-
} else {
4081-
/* The table is already in the background drop list */
4082-
err = DB_ERROR;
40834022
}
40844023

4024+
/* We return DB_SUCCESS to MySQL though the drop will
4025+
happen lazily later */
4026+
err = DB_SUCCESS;
40854027
goto funct_exit;
40864028
}
40874029

@@ -4103,11 +4045,7 @@ row_drop_table_for_mysql(
41034045
lock_remove_all_on_table(table, TRUE);
41044046
ut_a(table->n_rec_locks == 0);
41054047
} else if (table->n_ref_count > 0 || table->n_rec_locks > 0) {
4106-
ibool added;
4107-
4108-
added = row_add_table_to_background_drop_list(table->name);
4109-
4110-
if (added) {
4048+
if (row_add_table_to_background_drop_list(table->id)) {
41114049
ut_print_timestamp(stderr);
41124050
fputs(" InnoDB: Warning: MySQL is"
41134051
" trying to drop table ", stderr);

0 commit comments

Comments
 (0)