Description:
1. if a table has name like `t-1`, it will be converted to `t@002d1`;
2. fil_op_replay_rename may add a fil_space_t with wrong name `t@002d1` to file
space cache directly which should be `t-1`;
3. when dd_load_tablespace try to search a cache with name `t-1` in cache, it will find a fil_space_t with name `t@002d1` and then cause some error;
4. ddl rollback may be a typical bad case and if a table is encrypted, it will report another error
5. Too many tables make this occur with a higher probability
How to repeat:
diff --git a/mysql-test/suite/innodb/t/rename_tablespace_with_reserved_name.test b/m
ysql-test/suite/innodb/t/rename_tablespace_with_reserved_name.test
new file mode 100644
index 00000000000..2ab80bc6e17
--- /dev/null
+++ b/mysql-test/suite/innodb/t/rename_tablespace_with_reserved_name.test
@@ -0,0 +1,75 @@
+--source include/have_debug.inc
+
+--echo #
+--echo # bad case 1: post_ddl in truncate table may pollute fil_space cache
+--echo #
+set global debug = "+d,force_intern_close_table";
+set global debug = "+d,ib_force_evict_all_table";
+
+create table `t-1` (a int key, b int);
+set global debug = "+d,ib_truncate_fail_after_rename";
+--error ER_GET_ERRNO
+truncate table `t-1`;
+
+# This select clear dict_table_t->ddl_not_evictable.
+select a from `t-1`;
+# Sleep to wait dict cache evicted
+--sleep 5
+
+--error ER_TABLESPACE_MISSING
+select a from `t-1`;
+drop table `t-1`;
+
+--let $restart_parameters=restart:
+--source include/restart_mysqld.inc
+
+--echo #
+--echo # bad case 2: TDE will report error after space cache pullution
+--echo #
+
+let $restart_parameters = restart: --early-plugin-load=keyring_file=$KEYRING_PLUGIN
--loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring $KEYRING_PLUGIN_OPT;
+--source include/restart_mysqld_no_echo.inc
+
+set global debug = "reset";
+set global debug = "+d,force_intern_close_table";
+set global debug = "+d,ib_force_evict_all_table";
+--sleep 5
+
+delimiter |;
+create procedure populate(IN `cnt` INT)
+begin
+ declare i int default 1;
+ while (i <= cnt) do
+ insert into `t-1` (`type`, `info`) values (repeat("#",3000), repeat("#",5));
+ set i = i + 1;
+ end while;
+end |
+delimiter ;|
+
+create table `t-1` (
+ `id` int primary key auto_increment,
+ `type` text DEFAULT NULL,
+ `info` varchar(50) DEFAULT NULL
+) engine=InnoDB encryption='Y';
+
+call populate(5);
+
+set global debug = "+d,ib_truncate_fail_after_rename";
+--error ER_GET_ERRNO
+truncate table `t-1`;
+
+# This select clear dict_table_t->ddl_not_evictable.
+select id from `t-1`;
+# Sleep to wait dict cache evicted
+--sleep 5
+
+--error ER_CANNOT_FIND_KEY_IN_KEYRING
+call populate(5);
+
+drop procedure populate;
+drop table `t-1`;
+set global debug = "reset";
+
+remove_file $MYSQL_TMP_DIR/mysecret_keyring;
+--let $restart_parameters=restart:
+--source include/restart_mysqld.inc
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index cc0c3ff8971..a8cd720c120 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -987,7 +987,8 @@ void release_table_share(TABLE_SHARE *share) {
assert(share->ref_count() != 0);
if (share->decrement_ref_count() == 0) {
- if (share->has_old_version() || table_def_shutdown_in_progress)
+ if (share->has_old_version() || table_def_shutdown_in_progress ||
+ DBUG_EVALUATE_IF("force_intern_close_table", true, false))
table_def_cache->erase(to_string(share->table_cache_key));
else {
/* Link share last in used_table_share list */
@@ -1714,7 +1715,8 @@ static void release_or_close_table(THD *thd, TABLE *table) {
tc->lock();
if (table->s->has_old_version() || table->has_invalid_dict() ||
- table->has_invalid_stats() || table_def_shutdown_in_progress) {
+ table->has_invalid_stats() || table_def_shutdown_in_progress ||
+ DBUG_EVALUATE_IF("force_intern_close_table", true, false)) {
tc->remove_table(table);
mysql_mutex_lock(&LOCK_open);
intern_close_table(table);
diff --git a/storage/innobase/dict/dict0dd.cc b/storage/innobase/dict/dict0dd.cc
index e77568a2f2b..7b59bd99ca8 100644
--- a/storage/innobase/dict/dict0dd.cc
+++ b/storage/innobase/dict/dict0dd.cc
@@ -4636,7 +4636,7 @@ void dd_load_tablespace(const Table *dd_table, dict_table_t *t
able,
}
auto is_already_opened = [&]() {
- if (fil_space_exists_in_mem(table->space, space_name, false, true)) {
+ if (fil_space_exists_in_mem(table->space, space_name, true, true)) {
dd_get_and_save_data_dir_path(table, dd_table, true);
ut::free(shared_space_name);
return true;
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index d8c8f6c6c15..a3299483850 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1327,6 +1327,11 @@ ulint dict_make_room_in_cache(
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
ut_ad(dict_lru_validate());
+ DBUG_EXECUTE_IF("ib_force_evict_all_table", {
+ max_tables = 0;
+ pct_check = 100;
+ });
+
i = len = UT_LIST_GET_LEN(dict_sys->table_LRU);
if (len < max_tables) {
Suggested fix:
Convert space name(`t@002d2`) back to user-defined format(`t-2`) in fil_op_replay_rename