Commit 867617a9 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-18309: InnoDB reports bogus errors about missing #sql-*.ibd on startup

This is a follow-up to MDEV-18733. As part of that fix, we made
dict_check_sys_tables() skip tables that would be dropped by
row_mysql_drop_garbage_tables().

DICT_ERR_IGNORE_DROP: A new mode where the file should not be attempted
to be opened.

dict_load_tablespace(): Do not try to load the tablespace if
DICT_ERR_IGNORE_DROP has been specified.

row_mysql_drop_garbage_tables(): Pass the DICT_ERR_IGNORE_DROP mode.

fil_space_for_table_exists_in_mem(): Remove a parameter.
The only caller that passed print_error_if_does_not_exist=true
was row_drop_single_table_tablespace().
parent 6b3e2ec1
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# Embedded server does not support restarting # Embedded server does not support restarting
--source include/not_embedded.inc --source include/not_embedded.inc
let $MYSQLD_DATADIR=`select @@datadir`;
CREATE TABLE t(c0 SERIAL, c1 INT, c2 INT, c3 INT, c4 INT, CREATE TABLE t(c0 SERIAL, c1 INT, c2 INT, c3 INT, c4 INT,
KEY(c1), KEY(c2), KEY(c2,c1), KEY(c1), KEY(c2), KEY(c2,c1),
KEY(c3), KEY(c3,c1), KEY(c3,c2), KEY(c3,c2,c1), KEY(c3), KEY(c3,c1), KEY(c3,c2), KEY(c3,c2,c1),
...@@ -32,7 +34,9 @@ CREATE TABLE target (PRIMARY KEY(c1)) ENGINE=InnoDB SELECT * FROM t; ...@@ -32,7 +34,9 @@ CREATE TABLE target (PRIMARY KEY(c1)) ENGINE=InnoDB SELECT * FROM t;
--error ER_NO_SUCH_TABLE --error ER_NO_SUCH_TABLE
SELECT * from target; SELECT * from target;
DROP TABLE t; DROP TABLE t;
--source include/restart_mysqld.inc --source include/shutdown_mysqld.inc
--remove_files_wildcard $MYSQLD_DATADIR/test #sql-*.ibd
--source include/start_mysqld.inc
CREATE TABLE t (a INT) ENGINE=InnoDB; CREATE TABLE t (a INT) ENGINE=InnoDB;
DROP TABLE t; DROP TABLE t;
--error ER_BAD_TABLE_ERROR --error ER_BAD_TABLE_ERROR
......
...@@ -1449,8 +1449,7 @@ static ulint dict_check_sys_tables() ...@@ -1449,8 +1449,7 @@ static ulint dict_check_sys_tables()
/* Now that we have the proper name for this tablespace, /* Now that we have the proper name for this tablespace,
look to see if it is already in the tablespace cache. */ look to see if it is already in the tablespace cache. */
if (fil_space_for_table_exists_in_mem( if (fil_space_for_table_exists_in_mem(
space_id, table_name.m_name, space_id, table_name.m_name, NULL, flags)) {
false, NULL, flags)) {
/* Recovery can open a datafile that does not /* Recovery can open a datafile that does not
match SYS_DATAFILES. If they don't match, update match SYS_DATAFILES. If they don't match, update
SYS_DATAFILES. */ SYS_DATAFILES. */
...@@ -2845,7 +2844,12 @@ dict_load_tablespace( ...@@ -2845,7 +2844,12 @@ dict_load_tablespace(
/* The tablespace may already be open. */ /* The tablespace may already be open. */
if (fil_space_for_table_exists_in_mem( if (fil_space_for_table_exists_in_mem(
table->space, space_name, false, heap, table->flags)) { table->space, space_name, heap, table->flags)) {
return;
}
if (ignore_err == DICT_ERR_IGNORE_DROP) {
table->file_unreadable = true;
return; return;
} }
......
...@@ -4540,9 +4540,6 @@ memory cache. Note that if we have not done a crash recovery at the database ...@@ -4540,9 +4540,6 @@ memory cache. Note that if we have not done a crash recovery at the database
startup, there may be many tablespaces which are not yet in the memory cache. startup, there may be many tablespaces which are not yet in the memory cache.
@param[in] id Tablespace ID @param[in] id Tablespace ID
@param[in] name Tablespace name used in fil_space_create(). @param[in] name Tablespace name used in fil_space_create().
@param[in] print_error_if_does_not_exist
Print detailed error information to the
error log if a matching tablespace is not found from memory.
@param[in] heap Heap memory @param[in] heap Heap memory
@param[in] table_flags table flags @param[in] table_flags table flags
@return true if a matching tablespace exists in the memory cache */ @return true if a matching tablespace exists in the memory cache */
...@@ -4550,11 +4547,9 @@ bool ...@@ -4550,11 +4547,9 @@ bool
fil_space_for_table_exists_in_mem( fil_space_for_table_exists_in_mem(
ulint id, ulint id,
const char* name, const char* name,
bool print_error_if_does_not_exist,
mem_heap_t* heap, mem_heap_t* heap,
ulint table_flags) ulint table_flags)
{ {
fil_space_t* fnamespace;
fil_space_t* space; fil_space_t* space;
const ulint expected_flags = dict_tf_to_fsp_flags(table_flags); const ulint expected_flags = dict_tf_to_fsp_flags(table_flags);
...@@ -4568,58 +4563,10 @@ fil_space_for_table_exists_in_mem( ...@@ -4568,58 +4563,10 @@ fil_space_for_table_exists_in_mem(
/* Look if there is a space with the same name; the name is the /* Look if there is a space with the same name; the name is the
directory path from the datadir to the file */ directory path from the datadir to the file */
fnamespace = fil_space_get_by_name(name); const bool valid = space
bool valid = space && !((space->flags ^ expected_flags) && !((space->flags ^ expected_flags) & ~FSP_FLAGS_MEM_MASK)
& ~FSP_FLAGS_MEM_MASK); && space == fil_space_get_by_name(name);
if (!space) {
} else if (!valid || space == fnamespace) {
/* Found with the same file name, or got a flag mismatch. */
goto func_exit;
}
if (!print_error_if_does_not_exist) {
valid = false;
goto func_exit;
}
if (space == NULL) {
if (fnamespace == NULL) {
if (print_error_if_does_not_exist) {
fil_report_missing_tablespace(name, id);
}
} else {
ib::error() << "Table " << name << " in InnoDB data"
" dictionary has tablespace id " << id
<< ", but a tablespace with that id does not"
" exist. There is a tablespace of name "
<< fnamespace->name << " and id "
<< fnamespace->id << ", though. Have you"
" deleted or moved .ibd files?";
}
error_exit:
ib::info() << TROUBLESHOOT_DATADICT_MSG;
valid = false;
goto func_exit;
}
if (0 != strcmp(space->name, name)) {
ib::error() << "Table " << name << " in InnoDB data dictionary"
" has tablespace id " << id << ", but the tablespace"
" with that id has name " << space->name << "."
" Have you deleted or moved .ibd files?";
if (fnamespace != NULL) {
ib::error() << "There is a tablespace with the right"
" name: " << fnamespace->name << ", but its id"
" is " << fnamespace->id << ".";
}
goto error_exit;
}
func_exit:
if (valid) { if (valid) {
/* Adjust the flags that are in FSP_FLAGS_MEM_MASK. /* Adjust the flags that are in FSP_FLAGS_MEM_MASK.
FSP_SPACE_FLAGS will not be written back here. */ FSP_SPACE_FLAGS will not be written back here. */
......
...@@ -70,7 +70,10 @@ enum dict_err_ignore_t { ...@@ -70,7 +70,10 @@ enum dict_err_ignore_t {
Silently load a missing Silently load a missing
tablespace, and do not load tablespace, and do not load
incomplete index definitions. */ incomplete index definitions. */
DICT_ERR_IGNORE_ALL = 0xFFFF /*!< ignore all errors */ /** ignore all errors above */
DICT_ERR_IGNORE_ALL = 15,
/** prepare to drop the table; do not attempt to load tablespace */
DICT_ERR_IGNORE_DROP = 31
}; };
/** Quiescing states for flushing tables to disk. */ /** Quiescing states for flushing tables to disk. */
......
...@@ -1162,9 +1162,6 @@ memory cache. Note that if we have not done a crash recovery at the database ...@@ -1162,9 +1162,6 @@ memory cache. Note that if we have not done a crash recovery at the database
startup, there may be many tablespaces which are not yet in the memory cache. startup, there may be many tablespaces which are not yet in the memory cache.
@param[in] id Tablespace ID @param[in] id Tablespace ID
@param[in] name Tablespace name used in fil_space_create(). @param[in] name Tablespace name used in fil_space_create().
@param[in] print_error_if_does_not_exist
Print detailed error information to the
error log if a matching tablespace is not found from memory.
@param[in] heap Heap memory @param[in] heap Heap memory
@param[in] table_flags table flags @param[in] table_flags table flags
@return true if a matching tablespace exists in the memory cache */ @return true if a matching tablespace exists in the memory cache */
...@@ -1172,7 +1169,6 @@ bool ...@@ -1172,7 +1169,6 @@ bool
fil_space_for_table_exists_in_mem( fil_space_for_table_exists_in_mem(
ulint id, ulint id,
const char* name, const char* name,
bool print_error_if_does_not_exist,
mem_heap_t* heap, mem_heap_t* heap,
ulint table_flags); ulint table_flags);
......
...@@ -2675,7 +2675,7 @@ row_mysql_drop_garbage_tables() ...@@ -2675,7 +2675,7 @@ row_mysql_drop_garbage_tables()
btr_pcur_commit_specify_mtr(&pcur, &mtr); btr_pcur_commit_specify_mtr(&pcur, &mtr);
if (dict_load_table(table_name, true, if (dict_load_table(table_name, true,
DICT_ERR_IGNORE_ALL)) { DICT_ERR_IGNORE_DROP)) {
row_drop_table_for_mysql( row_drop_table_for_mysql(
table_name, trx, table_name, trx,
SQLCOM_DROP_TABLE); SQLCOM_DROP_TABLE);
...@@ -3231,7 +3231,7 @@ row_drop_single_table_tablespace( ...@@ -3231,7 +3231,7 @@ row_drop_single_table_tablespace(
/* If the tablespace is not in the cache, just delete the file. */ /* If the tablespace is not in the cache, just delete the file. */
if (!fil_space_for_table_exists_in_mem( if (!fil_space_for_table_exists_in_mem(
space_id, tablename, true, NULL, table_flags)) { space_id, tablename, NULL, table_flags)) {
/* Force a delete of any discarded or temporary files. */ /* Force a delete of any discarded or temporary files. */
fil_delete_file(filepath); fil_delete_file(filepath);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment