diff options
51 files changed, 918 insertions, 1324 deletions
diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index a0b09d434f7..223f8d56ecf 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -71,7 +71,6 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include <btr0sea.h> -#include <dict0priv.h> #include <lock0lock.h> #include <log0recv.h> #include <log0crypt.h> @@ -3315,19 +3314,18 @@ static void xb_load_single_table_tablespace(const char *dirname, name[pathlen - 5] = 0; } + const fil_space_t::name_type n{name, pathlen - 5}; Datafile *file; if (is_remote) { RemoteDatafile* rf = new RemoteDatafile(); - if (!rf->open_link_file(name)) { + if (!rf->open_link_file(n)) { die("Can't open datafile %s", name); } file = rf; } else { file = new Datafile(); - file->make_filepath(".", - fil_space_t::name_type{name, strlen(name)}, - IBD); + file->make_filepath(".", n, IBD); } if (file->open_read_only(true) != DB_SUCCESS) { diff --git a/mysql-test/suite/innodb/r/restart.result b/mysql-test/suite/innodb/r/restart.result index 9bbcc3285cf..ea9734d5a01 100644 --- a/mysql-test/suite/innodb/r/restart.result +++ b/mysql-test/suite/innodb/r/restart.result @@ -7,7 +7,7 @@ call mtr.add_suppression("\\[ERROR\\] InnoDB: Tablespace flags are invalid in datafile: .*test.t[rcd]\\.ibd"); call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number .* in a file operation\\."); call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified\\."); -call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for `test`\\.`td` because it could not be opened\\."); +call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for test/td because it could not be opened\\."); CREATE TABLE tr(a INT)ENGINE=InnoDB ROW_FORMAT=REDUNDANT; CREATE TABLE tc(a INT)ENGINE=InnoDB ROW_FORMAT=COMPACT PAGE_COMPRESSED=1 PAGE_COMPRESSION_LEVEL=9; diff --git a/mysql-test/suite/innodb/r/row_format_redundant.result b/mysql-test/suite/innodb/r/row_format_redundant.result index 0eede61b175..f354666f645 100644 --- a/mysql-test/suite/innodb/r/row_format_redundant.result +++ b/mysql-test/suite/innodb/r/row_format_redundant.result @@ -75,7 +75,7 @@ DROP TABLE t1; Warnings: Warning 1932 Table 'test.t1' doesn't exist in engine DROP TABLE t2,t3; -FOUND 5 /\[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err +FOUND 5 /\[ERROR\] InnoDB: Table test/t1 in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b/ in mysqld.1.err # restart ib_buffer_pool ib_logfile0 diff --git a/mysql-test/suite/innodb/r/table_flags.result b/mysql-test/suite/innodb/r/table_flags.result index 210d370aab4..ce71d9b022d 100644 --- a/mysql-test/suite/innodb/r/table_flags.result +++ b/mysql-test/suite/innodb/r/table_flags.result @@ -122,8 +122,8 @@ a 42 SHOW CREATE TABLE tp; ERROR 42S02: Table 'test.tp' doesn't exist in engine -FOUND 5 /InnoDB: Table `test`.`t[cp]` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649/ in mysqld.1.err -FOUND 2 /InnoDB: Table `test`\.`tr` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b/ in mysqld.1.err +FOUND 5 /InnoDB: Table test/t[cp] in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649/ in mysqld.1.err +FOUND 2 /InnoDB: Table test/tr in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b/ in mysqld.1.err Restoring SYS_TABLES clustered index root page (8) # restart: with restart_parameters SHOW CREATE TABLE tr; diff --git a/mysql-test/suite/innodb/r/truncate_missing.result b/mysql-test/suite/innodb/r/truncate_missing.result index 938bd5f2213..1cc654f0d7e 100644 --- a/mysql-test/suite/innodb/r/truncate_missing.result +++ b/mysql-test/suite/innodb/r/truncate_missing.result @@ -1,6 +1,6 @@ call mtr.add_suppression("InnoDB: Operating system error number "); call mtr.add_suppression("InnoDB: (The error means|If you are|Cannot open datafile) "); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\.`t`"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t "); call mtr.add_suppression("InnoDB: Table test/t .* does not exist"); CREATE TABLE t (a SERIAL) ENGINE=InnoDB; INSERT INTO t() VALUES(); diff --git a/mysql-test/suite/innodb/t/alter_missing_tablespace.test b/mysql-test/suite/innodb/t/alter_missing_tablespace.test index c615c9ff537..bf7111509bd 100644 --- a/mysql-test/suite/innodb/t/alter_missing_tablespace.test +++ b/mysql-test/suite/innodb/t/alter_missing_tablespace.test @@ -10,7 +10,7 @@ call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: "); call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation"); call mtr.add_suppression("InnoDB: The error means the system cannot find the path specified"); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`\(t\|x\.\.d\)` because it could not be opened"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/\(t\|x@002e@002ed\) because it could not be opened"); call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing"); call mtr.add_suppression("Could not find a valid tablespace file for"); call mtr.add_suppression("InnoDB: Failed to find tablespace for table `test`\.`\(t\|x\.\.d\)` in the cache"); diff --git a/mysql-test/suite/innodb/t/log_file_name.test b/mysql-test/suite/innodb/t/log_file_name.test index f6a32b93dd9..534c4e6984f 100644 --- a/mysql-test/suite/innodb/t/log_file_name.test +++ b/mysql-test/suite/innodb/t/log_file_name.test @@ -164,7 +164,7 @@ call mtr.add_suppression("InnoDB: The error means the system cannot find the pat call mtr.add_suppression("InnoDB: .*you must create directories"); call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*u[1-5]\.ibd'"); call mtr.add_suppression("InnoDB: Could not find a valid tablespace file for `test/u[1-5]`"); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`u[1-3]` because it could not be opened."); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/u[1-3] because it could not be opened\\."); call mtr.add_suppression("InnoDB: Failed to find tablespace for table .* in the cache. Attempting to load the tablespace with space id"); call mtr.add_suppression("InnoDB: Plugin initialization aborted"); call mtr.add_suppression("Plugin 'InnoDB' \(init function returned error\|registration as a STORAGE ENGINE failed\)"); diff --git a/mysql-test/suite/innodb/t/restart.test b/mysql-test/suite/innodb/t/restart.test index 2af0f2dd570..a5f2e5a42e8 100644 --- a/mysql-test/suite/innodb/t/restart.test +++ b/mysql-test/suite/innodb/t/restart.test @@ -18,7 +18,7 @@ let page_size= `select @@innodb_page_size`; call mtr.add_suppression("\\[ERROR\\] InnoDB: Tablespace flags are invalid in datafile: .*test.t[rcd]\\.ibd"); call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number .* in a file operation\\."); call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified\\."); -call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for `test`\\.`td` because it could not be opened\\."); +call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace for test/td because it could not be opened\\."); CREATE TABLE tr(a INT)ENGINE=InnoDB ROW_FORMAT=REDUNDANT; CREATE TABLE tc(a INT)ENGINE=InnoDB ROW_FORMAT=COMPACT diff --git a/mysql-test/suite/innodb/t/row_format_redundant.test b/mysql-test/suite/innodb/t/row_format_redundant.test index e8869b886c8..aadbfd2b773 100644 --- a/mysql-test/suite/innodb/t/row_format_redundant.test +++ b/mysql-test/suite/innodb/t/row_format_redundant.test @@ -4,7 +4,7 @@ --disable_query_log call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found"); -call mtr.add_suppression("InnoDB: Table `test`.`t1` in InnoDB data dictionary contains invalid flags. SYS_TABLES\\.TYPE=1 SYS_TABLES\\.MIX_LEN=511\\r?$"); +call mtr.add_suppression("InnoDB: Table test/t1 in InnoDB data dictionary contains invalid flags. SYS_TABLES\\.TYPE=1 SYS_TABLES\\.MIX_LEN=511\\r?$"); call mtr.add_suppression("InnoDB: Parent table of FTS auxiliary table test/FTS_.* not found"); call mtr.add_suppression("InnoDB: Cannot open table test/t1 from the internal data dictionary"); call mtr.add_suppression("InnoDB: Table `test`.`t1` does not exist in the InnoDB internal data dictionary though MariaDB is trying to (rename|drop)"); @@ -153,7 +153,7 @@ RENAME TABLE t1 TO tee_one; DROP TABLE t1; DROP TABLE t2,t3; ---let SEARCH_PATTERN= \[ERROR\] InnoDB: Table `test`\.`t1` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b +--let SEARCH_PATTERN= \[ERROR\] InnoDB: Table test/t1 in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=1 SYS_TABLES\.MIX_LEN=511\b --source include/search_pattern_in_file.inc --let $restart_parameters= diff --git a/mysql-test/suite/innodb/t/table_flags.test b/mysql-test/suite/innodb/t/table_flags.test index b037e46fb4f..f3a2c856af2 100644 --- a/mysql-test/suite/innodb/t/table_flags.test +++ b/mysql-test/suite/innodb/t/table_flags.test @@ -6,8 +6,8 @@ --disable_query_log call mtr.add_suppression("InnoDB: Table `mysql`\\.`innodb_table_stats` not found"); call mtr.add_suppression("InnoDB: incorrect flags in SYS_TABLES"); -call mtr.add_suppression("InnoDB: Table `test`.`t[cp]` in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=(129|289|3873|1232[31]) SYS_TABLES\\.N_COLS=2147483649\\r?$"); -call mtr.add_suppression("InnoDB: Table `test`\\.`tr` in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=65 SYS_TABLES\\.MIX_LEN=4294967295\\r?$"); +call mtr.add_suppression("InnoDB: Table test/t[cp] in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=(129|289|3873|1232[31]) SYS_TABLES\\.N_COLS=2147483649\\r?$"); +call mtr.add_suppression("InnoDB: Table test/tr in InnoDB data dictionary contains invalid flags\\. SYS_TABLES\\.TYPE=65 SYS_TABLES\\.MIX_LEN=4294967295\\r?$"); call mtr.add_suppression("InnoDB: Refusing to load '\\..test.td\\.ibd' \\(id=3, flags=0x([2e]1)\\); dictionary contains id=3, flags=0x100\\1\\r?$"); call mtr.add_suppression("InnoDB: Refusing to load '\\..test.td\\.ibd' \\(id=3, flags=0x(1[2ae]1)\\); dictionary contains id=3, flags=0x10\\1\\r?$"); call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`.`td` because it could not be opened\\."); @@ -170,9 +170,9 @@ SHOW CREATE TABLE tp; --source include/shutdown_mysqld.inc let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err; ---let SEARCH_PATTERN= InnoDB: Table `test`.`t[cp]` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649 +--let SEARCH_PATTERN= InnoDB: Table test/t[cp] in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=(129|289|3873|1232[13]) SYS_TABLES\.N_COLS=2147483649 --source include/search_pattern_in_file.inc ---let SEARCH_PATTERN= InnoDB: Table `test`\.`tr` in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b +--let SEARCH_PATTERN= InnoDB: Table test/tr in InnoDB data dictionary contains invalid flags\. SYS_TABLES\.TYPE=65 SYS_TABLES\.MIX_LEN=4294967295\b --source include/search_pattern_in_file.inc # Restore the backup of the corrupted SYS_TABLES clustered index root page diff --git a/mysql-test/suite/innodb/t/truncate_missing.test b/mysql-test/suite/innodb/t/truncate_missing.test index c357f5bae72..fb6bd678237 100644 --- a/mysql-test/suite/innodb/t/truncate_missing.test +++ b/mysql-test/suite/innodb/t/truncate_missing.test @@ -3,7 +3,7 @@ call mtr.add_suppression("InnoDB: Operating system error number "); call mtr.add_suppression("InnoDB: (The error means|If you are|Cannot open datafile) "); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\.`t`"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t "); call mtr.add_suppression("InnoDB: Table test/t .* does not exist"); CREATE TABLE t (a SERIAL) ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb_fts/t/crash_recovery.test b/mysql-test/suite/innodb_fts/t/crash_recovery.test index fe58ca0addf..d5518b91590 100644 --- a/mysql-test/suite/innodb_fts/t/crash_recovery.test +++ b/mysql-test/suite/innodb_fts/t/crash_recovery.test @@ -252,7 +252,7 @@ if (!$have_debug) call mtr.add_suppression("InnoDB: Cannot (read first page of|open datafile for read-only:) '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd'"); call mtr.add_suppression("InnoDB: Datafile '\\./test/(FTS_|#sql-(alter|backup)-).*\\.ibd' is corrupted"); call mtr.add_suppression("InnoDB: (The error means|Operating system error)"); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`(FTS_|#sql-(backup|alter)-).*` because it could not be opened\\."); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/(FTS_|#sql-(backup|alter)-).* because it could not be opened\\."); call mtr.add_suppression("InnoDB: Expected tablespace id [1-9][0-9]* but found 0 in the file .*/test/(FTS_|#sql-(alter|backup)-).*\\.ibd"); --enable_query_log } diff --git a/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result b/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result index 92886ef7505..8708f26a653 100644 --- a/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result +++ b/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result @@ -7,7 +7,7 @@ call mtr.add_suppression("InnoDB: Unknown index id .* on page"); call mtr.add_suppression("InnoDB: Operating system error number"); call mtr.add_suppression("InnoDB: The error means"); call mtr.add_suppression("InnoDB: Cannot open datafile .*t1\\.ibd"); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t1`"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t1 "); FLUSH TABLES; SET SESSION innodb_strict_mode=1; CREATE TABLE t1 (c1 INT) ENGINE = Innodb diff --git a/mysql-test/suite/innodb_zip/t/wl5522_debug_zip.test b/mysql-test/suite/innodb_zip/t/wl5522_debug_zip.test index a543fc956d4..0c9bcb6cf9d 100644 --- a/mysql-test/suite/innodb_zip/t/wl5522_debug_zip.test +++ b/mysql-test/suite/innodb_zip/t/wl5522_debug_zip.test @@ -23,7 +23,7 @@ call mtr.add_suppression("InnoDB: Unknown index id .* on page"); call mtr.add_suppression("InnoDB: Operating system error number"); call mtr.add_suppression("InnoDB: The error means"); call mtr.add_suppression("InnoDB: Cannot open datafile .*t1\\.ibd"); -call mtr.add_suppression("InnoDB: Ignoring tablespace for `test`\\.`t1`"); +call mtr.add_suppression("InnoDB: Ignoring tablespace for test/t1 "); FLUSH TABLES; let MYSQLD_DATADIR =`SELECT @@datadir`; diff --git a/mysql-test/suite/mariabackup/missing_ibd.test b/mysql-test/suite/mariabackup/missing_ibd.test index 5e34b873b09..dc1406039e7 100644 --- a/mysql-test/suite/mariabackup/missing_ibd.test +++ b/mysql-test/suite/mariabackup/missing_ibd.test @@ -12,7 +12,7 @@ call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: '.*test.t1 call mtr.add_suppression('InnoDB: Operating system error number'); call mtr.add_suppression('InnoDB: The error means the system cannot find the path specified\.'); call mtr.add_suppression('InnoDB: Table test/t1 in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist'); -call mtr.add_suppression('InnoDB: Ignoring tablespace for `test`\.`t1` because it could not be opened\.'); +call mtr.add_suppression('InnoDB: Ignoring tablespace for test/t1 because it could not be opened\.'); --enable_query_log --source include/shutdown_mysqld.inc diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index 35a1330cbd2..222e671a900 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -115,8 +115,6 @@ SET(INNOBASE_SOURCES include/dict0mem.ic include/dict0pagecompress.h include/dict0pagecompress.ic - include/dict0priv.h - include/dict0priv.ic include/dict0stats.h include/dict0stats.ic include/dict0stats_bg.h diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc index afe8b5ec165..2792f71376d 100644 --- a/storage/innobase/dict/dict0boot.cc +++ b/storage/innobase/dict/dict0boot.cc @@ -96,45 +96,41 @@ void dict_hdr_flush_row_id(row_id_t id) mtr.commit(); } -/*****************************************************************//** -Creates the file page for the dictionary header. This function is -called only at the database creation. -@return TRUE if succeed */ -static -ibool -dict_hdr_create( -/*============*/ - mtr_t* mtr) /*!< in: mtr */ +/** Create the DICT_HDR page on database initialization. +@return whether the operation failed */ +static bool dict_hdr_create() { buf_block_t* block; ulint root_page_no; - ut_ad(mtr); + bool fail = false; + mtr_t mtr; + mtr.start(); compile_time_assert(DICT_HDR_SPACE == 0); /* Create the dictionary header file block in a new, allocated file segment in the system tablespace */ block = fseg_create(fil_system.sys_space, - DICT_HDR + DICT_HDR_FSEG_HEADER, mtr); + DICT_HDR + DICT_HDR_FSEG_HEADER, &mtr); ut_a(block->page.id() == page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO)); - buf_block_t* d = dict_hdr_get(mtr); + buf_block_t* d = dict_hdr_get(&mtr); /* Start counting row, table, index, and tree ids from DICT_HDR_FIRST_ID */ - mtr->write<8>(*d, DICT_HDR + DICT_HDR_ROW_ID + d->frame, - DICT_HDR_FIRST_ID); - mtr->write<8>(*d, DICT_HDR + DICT_HDR_TABLE_ID + d->frame, - DICT_HDR_FIRST_ID); - mtr->write<8>(*d, DICT_HDR + DICT_HDR_INDEX_ID + d->frame, - DICT_HDR_FIRST_ID); + mtr.write<8>(*d, DICT_HDR + DICT_HDR_ROW_ID + d->frame, + DICT_HDR_FIRST_ID); + mtr.write<8>(*d, DICT_HDR + DICT_HDR_TABLE_ID + d->frame, + DICT_HDR_FIRST_ID); + mtr.write<8>(*d, DICT_HDR + DICT_HDR_INDEX_ID + d->frame, + DICT_HDR_FIRST_ID); ut_ad(!mach_read_from_4(DICT_HDR + DICT_HDR_MAX_SPACE_ID + d->frame)); /* Obsolete, but we must initialize it anyway. */ - mtr->write<4>(*d, DICT_HDR + DICT_HDR_MIX_ID_LOW + d->frame, - DICT_HDR_FIRST_ID); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_MIX_ID_LOW + d->frame, + DICT_HDR_FIRST_ID); /* Create the B-tree roots for the clustered indexes of the basic system tables */ @@ -142,59 +138,55 @@ dict_hdr_create( /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, fil_system.sys_space, DICT_TABLES_ID, - nullptr, mtr); + nullptr, &mtr); if (root_page_no == FIL_NULL) { - - return(FALSE); +failed: + fail = true; + goto func_exit; } - mtr->write<4>(*d, DICT_HDR + DICT_HDR_TABLES + d->frame, root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLES + d->frame, root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_UNIQUE, fil_system.sys_space, DICT_TABLE_IDS_ID, - nullptr, mtr); + nullptr, &mtr); if (root_page_no == FIL_NULL) { - - return(FALSE); + goto failed; } - mtr->write<4>(*d, DICT_HDR + DICT_HDR_TABLE_IDS + d->frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_TABLE_IDS + d->frame, + root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, fil_system.sys_space, DICT_COLUMNS_ID, - nullptr, mtr); + nullptr, &mtr); if (root_page_no == FIL_NULL) { - - return(FALSE); + goto failed; } - mtr->write<4>(*d, DICT_HDR + DICT_HDR_COLUMNS + d->frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_COLUMNS + d->frame, + root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, fil_system.sys_space, DICT_INDEXES_ID, - nullptr, mtr); + nullptr, &mtr); if (root_page_no == FIL_NULL) { - - return(FALSE); + goto failed; } - mtr->write<4>(*d, DICT_HDR + DICT_HDR_INDEXES + d->frame, - root_page_no); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_INDEXES + d->frame, root_page_no); /*--------------------------*/ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE, fil_system.sys_space, DICT_FIELDS_ID, - nullptr, mtr); + nullptr, &mtr); if (root_page_no == FIL_NULL) { - - return(FALSE); + goto failed; } - mtr->write<4>(*d, DICT_HDR + DICT_HDR_FIELDS + d->frame, root_page_no); - /*--------------------------*/ - - return(TRUE); + mtr.write<4>(*d, DICT_HDR + DICT_HDR_FIELDS + d->frame, root_page_no); +func_exit: + mtr.commit(); + return fail; } /*****************************************************************//** @@ -210,23 +202,21 @@ dict_boot(void) mem_heap_t* heap; mtr_t mtr; - /* Be sure these constants do not ever change. To avoid bloat, - only check the *NUM_FIELDS* in each table */ - - ut_ad(DICT_NUM_COLS__SYS_TABLES == 8); - ut_ad(DICT_NUM_FIELDS__SYS_TABLES == 10); - ut_ad(DICT_NUM_FIELDS__SYS_TABLE_IDS == 2); - ut_ad(DICT_NUM_COLS__SYS_COLUMNS == 7); - ut_ad(DICT_NUM_FIELDS__SYS_COLUMNS == 9); - ut_ad(DICT_NUM_COLS__SYS_INDEXES == 8); - ut_ad(DICT_NUM_FIELDS__SYS_INDEXES == 10); - ut_ad(DICT_NUM_COLS__SYS_FIELDS == 3); - ut_ad(DICT_NUM_FIELDS__SYS_FIELDS == 5); - ut_ad(DICT_NUM_COLS__SYS_FOREIGN == 4); - ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN == 6); - ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2); - ut_ad(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4); - ut_ad(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6); + static_assert(DICT_NUM_COLS__SYS_TABLES == 8, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_TABLES == 10, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_TABLE_IDS == 2, "compatibility"); + static_assert(DICT_NUM_COLS__SYS_COLUMNS == 7, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_COLUMNS == 9, "compatibility"); + static_assert(DICT_NUM_COLS__SYS_INDEXES == 8, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_INDEXES == 10, "compatibility"); + static_assert(DICT_NUM_COLS__SYS_FIELDS == 3, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_FIELDS == 5, "compatibility"); + static_assert(DICT_NUM_COLS__SYS_FOREIGN == 4, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_FOREIGN == 6, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_FOREIGN_FOR_NAME == 2, + "compatibility"); + static_assert(DICT_NUM_COLS__SYS_FOREIGN_COLS == 4, "compatibility"); + static_assert(DICT_NUM_FIELDS__SYS_FOREIGN_COLS == 6, "compatibility"); mtr_start(&mtr); @@ -260,9 +250,9 @@ dict_boot(void) /* Insert into the dictionary cache the descriptions of the basic system tables */ /*-------------------------*/ - table = dict_mem_table_create("SYS_TABLES", fil_system.sys_space, - 8, 0, 0, 0); - + table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_TABLES], + fil_system.sys_space, + DICT_NUM_COLS__SYS_TABLES, 0, 0, 0); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, MAX_FULL_NAME_LEN); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 8); @@ -308,9 +298,9 @@ dict_boot(void) ut_a(error == DB_SUCCESS); /*-------------------------*/ - table = dict_mem_table_create("SYS_COLUMNS", fil_system.sys_space, - 7, 0, 0, 0); - + table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_COLUMNS], + fil_system.sys_space, + DICT_NUM_COLS__SYS_COLUMNS, 0, 0, 0); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0); @@ -341,8 +331,9 @@ dict_boot(void) UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); /*-------------------------*/ - table = dict_mem_table_create("SYS_INDEXES", fil_system.sys_space, - DICT_NUM_COLS__SYS_INDEXES, 0, 0, 0); + table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_INDEXES], + fil_system.sys_space, + DICT_NUM_COLS__SYS_INDEXES, 0, 0, 0); dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 8); @@ -383,9 +374,9 @@ dict_boot(void) UT_BITS_IN_BYTES(unsigned(table->indexes.start->n_nullable))); /*-------------------------*/ - table = dict_mem_table_create("SYS_FIELDS", fil_system.sys_space, - 3, 0, 0, 0); - + table = dict_table_t::create(dict_sys.SYS_TABLE[dict_sys.SYS_FIELDS], + fil_system.sys_space, + DICT_NUM_COLS__SYS_FIELDS, 0, 0, 0); dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 8); dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0); @@ -413,10 +404,6 @@ dict_boot(void) mtr_commit(&mtr); - /*-------------------------*/ - - /* Initialize the insert buffer table and index for each tablespace */ - dberr_t err = ibuf_init_at_db_start(); if (err == DB_SUCCESS) { @@ -426,44 +413,19 @@ dict_boot(void) dict_load_sys_table(dict_sys.sys_columns); dict_load_sys_table(dict_sys.sys_indexes); dict_load_sys_table(dict_sys.sys_fields); + dict_sys.mutex_unlock(); + dict_sys.load_sys_tables(); + } else { + dict_sys.mutex_unlock(); } - dict_sys.mutex_unlock(); - return(err); } /*****************************************************************//** -Inserts the basic system table data into themselves in the database -creation. */ -static -void -dict_insert_initial_data(void) -/*==========================*/ -{ - /* Does nothing yet */ -} - -/*****************************************************************//** Creates and initializes the data dictionary at the server bootstrap. @return DB_SUCCESS or error code. */ -dberr_t -dict_create(void) -/*=============*/ +dberr_t dict_create() { - mtr_t mtr; - - mtr_start(&mtr); - - dict_hdr_create(&mtr); - - mtr_commit(&mtr); - - dberr_t err = dict_boot(); - - if (err == DB_SUCCESS) { - dict_insert_initial_data(); - } - - return(err); + return dict_hdr_create() ? DB_ERROR : dict_boot(); } diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 1d2f4f1abb1..0efc8a89903 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -41,9 +41,9 @@ Created 1/8/1996 Heikki Tuuri #include "trx0rseg.h" #include "trx0undo.h" #include "ut0vec.h" -#include "dict0priv.h" #include "fts0priv.h" #include "srv0start.h" +#include "log.h" /*****************************************************************//** Based on a table object, this function builds the entry to be inserted @@ -897,6 +897,17 @@ rec_corrupted: return 0; } +/** @return whether SYS_TABLES.NAME is for a '#sql-ib' table */ +bool dict_table_t::is_garbage_name(const void *data, size_t size) +{ + constexpr size_t suffix= sizeof TEMP_FILE_PREFIX_INNODB; + if (size <= suffix) + return false; + const char *f= static_cast<const char*>(memchr(data, '/', size - suffix)); + return f && !memcmp(f + 1, TEMP_FILE_PREFIX_INNODB, + (sizeof TEMP_FILE_PREFIX_INNODB) - 1); +} + /*********************************************************************//** Creates a table create graph. @return own: table create node */ @@ -1315,259 +1326,196 @@ function_exit: return(thr); } -/****************************************************************//** -Check whether a system table exists. Additionally, if it exists, -move it to the non-LRU end of the table LRU list. This is only used -for system tables that can be upgraded or added to an older database, -which include SYS_FOREIGN and SYS_FOREIGN_COLS. -@return DB_SUCCESS if the sys table exists, DB_CORRUPTION if it exists -but is not current, DB_TABLE_NOT_FOUND if it does not exist*/ -static -dberr_t -dict_check_if_system_table_exists( -/*==============================*/ - const char* tablename, /*!< in: name of table */ - ulint num_fields, /*!< in: number of fields */ - ulint num_indexes) /*!< in: number of indexes */ -{ - dict_table_t* sys_table; - dberr_t error = DB_SUCCESS; - - ut_ad(!srv_any_background_activity()); - - dict_sys.mutex_lock(); - - sys_table = dict_table_get_low(tablename); - - if (sys_table == NULL) { - error = DB_TABLE_NOT_FOUND; - - } else if (UT_LIST_GET_LEN(sys_table->indexes) != num_indexes - || sys_table->n_cols != num_fields) { - error = DB_CORRUPTION; - - } else { - /* This table has already been created, and it is OK. - Ensure that it can't be evicted from the table LRU cache. */ - - dict_table_prevent_eviction(sys_table); - } - - dict_sys.mutex_unlock(); - - return(error); -} - -/****************************************************************//** -Creates the foreign key constraints system tables inside InnoDB -at server bootstrap or server start if they are not found or are -not of the right form. -@return DB_SUCCESS or error code */ -dberr_t -dict_create_or_check_foreign_constraint_tables(void) -/*================================================*/ +bool dict_sys_t::load_sys_tables() { - trx_t* trx; - my_bool srv_file_per_table_backup; - dberr_t err; - dberr_t sys_foreign_err; - dberr_t sys_foreign_cols_err; - - ut_ad(!srv_any_background_activity()); - - sys_foreign_err = dict_check_if_system_table_exists( - "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3); - sys_foreign_cols_err = dict_check_if_system_table_exists( - "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1); - - if (sys_foreign_err == DB_SUCCESS - && sys_foreign_cols_err == DB_SUCCESS) { - return(DB_SUCCESS); - } - - if (srv_read_only_mode - || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) { - return(DB_READ_ONLY); - } - - trx = trx_create(); - - trx->dict_operation = true; - - trx->op_info = "creating foreign key sys tables"; - - row_mysql_lock_data_dictionary(trx); - - DBUG_EXECUTE_IF( - "create_and_drop_garbage", - err = que_eval_sql( - NULL, - "PROCEDURE CREATE_GARBAGE_TABLE_PROC () IS\n" - "BEGIN\n" - "CREATE TABLE\n" - "\"test/" TEMP_FILE_PREFIX_INNODB "-garbage\"" - "(ID CHAR);\n" - "CREATE UNIQUE CLUSTERED INDEX PRIMARY ON " - "\"test/" TEMP_FILE_PREFIX_INNODB "-garbage\"(ID);\n" - "END;\n", FALSE, trx); - ut_ad(err == DB_SUCCESS); - row_drop_table_for_mysql("test/" - TEMP_FILE_PREFIX_INNODB "-garbage", - trx, SQLCOM_DROP_DB, true);); - - ib::info() << "Creating foreign key constraint system tables."; - - /* NOTE: in dict_load_foreigns we use the fact that - there are 2 secondary indexes on SYS_FOREIGN, and they - are defined just like below */ - - /* NOTE: when designing InnoDB's foreign key support in 2001, we made - an error and made the table names and the foreign key id of type - 'CHAR' (internally, really a VARCHAR). We should have made the type - VARBINARY, like in other InnoDB system tables, to get a clean - design. */ - - srv_file_per_table_backup = srv_file_per_table; - - /* We always want SYSTEM tables to be created inside the system - tablespace. */ - - srv_file_per_table = 0; - - err = que_eval_sql( - NULL, - "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n" - "BEGIN\n" - "CREATE TABLE\n" - "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR," - " REF_NAME CHAR, N_COLS INT);\n" - "CREATE UNIQUE CLUSTERED INDEX ID_IND" - " ON SYS_FOREIGN (ID);\n" - "CREATE INDEX FOR_IND" - " ON SYS_FOREIGN (FOR_NAME);\n" - "CREATE INDEX REF_IND" - " ON SYS_FOREIGN (REF_NAME);\n" - "CREATE TABLE\n" - "SYS_FOREIGN_COLS(ID CHAR, POS INT," - " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" - "CREATE UNIQUE CLUSTERED INDEX ID_IND" - " ON SYS_FOREIGN_COLS (ID, POS);\n" - "END;\n", - FALSE, trx); - - if (UNIV_UNLIKELY(err != DB_SUCCESS)) { - ib::error() << "Creation of SYS_FOREIGN and SYS_FOREIGN_COLS" - " failed: " << err; - - ut_ad(err == DB_OUT_OF_FILE_SPACE - || err == DB_TOO_MANY_CONCURRENT_TRXS); - trx->rollback(); - } else { - trx_commit_for_mysql(trx); - } - - row_mysql_unlock_data_dictionary(trx); - - trx->free(); - - srv_file_per_table = srv_file_per_table_backup; - - /* Note: The master thread has not been started at this point. */ - /* Confirm and move to the non-LRU part of the table LRU list. */ - sys_foreign_err = dict_check_if_system_table_exists( - "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3); - ut_a(sys_foreign_err == DB_SUCCESS); - - sys_foreign_cols_err = dict_check_if_system_table_exists( - "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1); - ut_a(sys_foreign_cols_err == DB_SUCCESS); - - return(err); + ut_ad(!srv_any_background_activity()); + bool mismatch= false; + mutex_lock(); + if (!(sys_foreign= load_table(SYS_TABLE[SYS_FOREIGN], + DICT_ERR_IGNORE_FK_NOKEY))); + else if (UT_LIST_GET_LEN(sys_foreign->indexes) == 3 && + sys_foreign->n_cols == DICT_NUM_COLS__SYS_FOREIGN + DATA_N_SYS_COLS) + prevent_eviction(sys_foreign); + else + { + sys_foreign= nullptr; + mismatch= true; + ib::error() << "Invalid definition of SYS_FOREIGN"; + } + if (!(sys_foreign_cols= load_table(SYS_TABLE[SYS_FOREIGN_COLS], + DICT_ERR_IGNORE_FK_NOKEY))); + else if (UT_LIST_GET_LEN(sys_foreign_cols->indexes) == 1 && + sys_foreign_cols->n_cols == + DICT_NUM_COLS__SYS_FOREIGN_COLS + DATA_N_SYS_COLS) + prevent_eviction(sys_foreign_cols); + else + { + sys_foreign_cols= nullptr; + mismatch= true; + ib::error() << "Invalid definition of SYS_FOREIGN_COLS"; + } + if (!(sys_virtual= load_table(SYS_TABLE[SYS_VIRTUAL], + DICT_ERR_IGNORE_FK_NOKEY))); + else if (UT_LIST_GET_LEN(sys_virtual->indexes) == 1 && + sys_virtual->n_cols == DICT_NUM_COLS__SYS_VIRTUAL + DATA_N_SYS_COLS) + prevent_eviction(sys_virtual); + else + { + sys_virtual= nullptr; + mismatch= true; + ib::error() << "Invalid definition of SYS_VIRTUAL"; + } + mutex_unlock(); + return mismatch; } -/** Creates the virtual column system table (SYS_VIRTUAL) inside InnoDB -at server bootstrap or server start if the table is not found or is -not of the right form. -@return DB_SUCCESS or error code */ -dberr_t -dict_create_or_check_sys_virtual() +dberr_t dict_sys_t::create_or_check_sys_tables() { - trx_t* trx; - my_bool srv_file_per_table_backup; - dberr_t err; - - ut_ad(!srv_any_background_activity()); - - err = dict_check_if_system_table_exists( - "SYS_VIRTUAL", DICT_NUM_FIELDS__SYS_VIRTUAL + 1, 1); - - if (err == DB_SUCCESS) { - dict_sys.mutex_lock(); - dict_sys.sys_virtual = dict_table_get_low("SYS_VIRTUAL"); - dict_sys.mutex_unlock(); - return(DB_SUCCESS); - } - - if (srv_read_only_mode - || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) { - return(DB_READ_ONLY); - } - - trx = trx_create(); - - trx->dict_operation = true; - - trx->op_info = "creating sys_virtual tables"; - - row_mysql_lock_data_dictionary(trx); - - ib::info() << "Creating sys_virtual system tables."; - - srv_file_per_table_backup = srv_file_per_table; - - /* We always want SYSTEM tables to be created inside the system - tablespace. */ + if (sys_tables_exist()) + return DB_SUCCESS; - srv_file_per_table = 0; + if (srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) + return DB_READ_ONLY; - err = que_eval_sql( - NULL, - "PROCEDURE CREATE_SYS_VIRTUAL_TABLES_PROC () IS\n" - "BEGIN\n" - "CREATE TABLE\n" - "SYS_VIRTUAL(TABLE_ID BIGINT, POS INT," - " BASE_POS INT);\n" - "CREATE UNIQUE CLUSTERED INDEX BASE_IDX" - " ON SYS_VIRTUAL(TABLE_ID, POS, BASE_POS);\n" - "END;\n", - FALSE, trx); + if (load_sys_tables()) + { + ib::info() << "Set innodb_read_only=1 or innodb_force_recovery=3" + " to start up"; + return DB_CORRUPTION; + } - if (UNIV_UNLIKELY(err != DB_SUCCESS)) { - ib::error() << "Creation of SYS_VIRTUAL failed: " << err; + if (sys_tables_exist()) + return DB_SUCCESS; - ut_ad(err == DB_OUT_OF_FILE_SPACE - || err == DB_TOO_MANY_CONCURRENT_TRXS); - trx->rollback(); - } else { - trx_commit_for_mysql(trx); - } + trx_t *trx= trx_create(); + trx->dict_operation = true; + row_mysql_lock_data_dictionary(trx); + + DBUG_EXECUTE_IF("create_and_drop_garbage", + ut_ad(DB_SUCCESS == que_eval_sql( + nullptr, + "PROCEDURE CREATE_GARBAGE_TABLE_PROC () IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "\"test/" TEMP_FILE_PREFIX_INNODB "-garbage\"" + "(ID CHAR);\n" + "CREATE UNIQUE CLUSTERED INDEX PRIMARY ON " + "\"test/" TEMP_FILE_PREFIX_INNODB + "-garbage\"(ID);\n" + "END;\n", false, trx)); + row_drop_table_for_mysql("test/" + TEMP_FILE_PREFIX_INNODB "-garbage", + trx, SQLCOM_DROP_DB, true);); + + /* NOTE: when designing InnoDB's foreign key support in 2001, Heikki Tuuri + made a mistake defined table names and the foreign key id to be of type + 'CHAR' (internally, really a VARCHAR). + The type should have been VARBINARY. */ + + const auto srv_file_per_table_backup= srv_file_per_table; + + /* We always want SYSTEM tables to be created inside the system + tablespace. */ + srv_file_per_table= 0; + dberr_t error; + const char *tablename; + + if (!sys_foreign) + { + error= que_eval_sql(nullptr, "PROCEDURE CREATE_FOREIGN() IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR," + " REF_NAME CHAR, N_COLS INT);\n" + "CREATE UNIQUE CLUSTERED INDEX ID_IND" + " ON SYS_FOREIGN (ID);\n" + "CREATE INDEX FOR_IND" + " ON SYS_FOREIGN (FOR_NAME);\n" + "CREATE INDEX REF_IND" + " ON SYS_FOREIGN (REF_NAME);\n" + "END;\n", false, trx); + if (UNIV_UNLIKELY(error != DB_SUCCESS)) + { + tablename= SYS_TABLE[SYS_FOREIGN].data(); +err_exit: + ib::error() << "Creation of " << tablename << " failed: " << error; + trx->rollback(); + row_mysql_unlock_data_dictionary(trx); + trx->free(); + srv_file_per_table= srv_file_per_table_backup; + return error; + } + } + if (!sys_foreign_cols) + { + error= que_eval_sql(nullptr, "PROCEDURE CREATE_FOREIGN_COLS() IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "SYS_FOREIGN_COLS(ID CHAR, POS INT," + " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n" + "CREATE UNIQUE CLUSTERED INDEX ID_IND" + " ON SYS_FOREIGN_COLS (ID, POS);\n" + "END;\n", false, trx); + if (UNIV_UNLIKELY(error != DB_SUCCESS)) + { + tablename= SYS_TABLE[SYS_FOREIGN_COLS].data(); + goto err_exit; + } + } + if (!sys_virtual) + { + error= que_eval_sql(nullptr, "PROCEDURE CREATE_VIRTUAL() IS\n" + "BEGIN\n" + "CREATE TABLE\n" + "SYS_VIRTUAL(TABLE_ID BIGINT,POS INT,BASE_POS INT);\n" + "CREATE UNIQUE CLUSTERED INDEX BASE_IDX" + " ON SYS_VIRTUAL(TABLE_ID, POS, BASE_POS);\n" + "END;\n", false, trx); + if (UNIV_UNLIKELY(error != DB_SUCCESS)) + { + tablename= SYS_TABLE[SYS_VIRTUAL].data(); + goto err_exit; + } + } - row_mysql_unlock_data_dictionary(trx); + trx->commit(); + row_mysql_unlock_data_dictionary(trx); + trx->free(); + srv_file_per_table= srv_file_per_table_backup; - trx->free(); + mutex_lock(); + if (sys_foreign); + else if (!(sys_foreign= load_table(SYS_TABLE[SYS_FOREIGN]))) + { + tablename= SYS_TABLE[SYS_FOREIGN].data(); +load_fail: + mutex_unlock(); + ib::error() << "Failed to CREATE TABLE " << tablename; + return DB_TABLE_NOT_FOUND; + } + else + prevent_eviction(sys_foreign); - srv_file_per_table = srv_file_per_table_backup; + if (sys_foreign_cols); + else if (!(sys_foreign_cols= load_table(SYS_TABLE[SYS_FOREIGN_COLS]))) + { + tablename= SYS_TABLE[SYS_FOREIGN_COLS].data(); + goto load_fail; + } + else + prevent_eviction(sys_foreign_cols); - /* Note: The master thread has not been started at this point. */ - /* Confirm and move to the non-LRU part of the table LRU list. */ - dberr_t sys_virtual_err = dict_check_if_system_table_exists( - "SYS_VIRTUAL", DICT_NUM_FIELDS__SYS_VIRTUAL + 1, 1); - ut_a(sys_virtual_err == DB_SUCCESS); - dict_sys.mutex_lock(); - dict_sys.sys_virtual = dict_table_get_low("SYS_VIRTUAL"); - dict_sys.mutex_unlock(); + if (sys_virtual); + else if (!(sys_virtual= load_table(SYS_TABLE[SYS_VIRTUAL]))) + { + tablename= SYS_TABLE[SYS_VIRTUAL].data(); + goto load_fail; + } + else + prevent_eviction(sys_virtual); - return(err); + mutex_unlock(); + return DB_SUCCESS; } /****************************************************************//** @@ -1959,35 +1907,19 @@ dict_create_add_foreigns_to_dictionary( const dict_table_t* table, trx_t* trx) { - dict_foreign_t* foreign; - dberr_t error; - - dict_sys.assert_locked(); - - if (NULL == dict_table_get_low("SYS_FOREIGN")) { - - ib::error() << "Table SYS_FOREIGN not found" - " in internal data dictionary"; + dict_sys.assert_locked(); - return(DB_ERROR); - } - - error = DB_SUCCESS; - - for (dict_foreign_set::const_iterator it = local_fk_set.begin(); - it != local_fk_set.end(); - ++it) { - - foreign = *it; - ut_ad(foreign->id != NULL); - - error = dict_create_add_foreign_to_dictionary( - table->name.m_name, foreign, trx); + if (!dict_sys.sys_foreign) + { + sql_print_error("InnoDB: Table SYS_FOREIGN not found" + " in internal data dictionary"); + return DB_ERROR; + } - if (error != DB_SUCCESS) { - break; - } - } + for (auto fk : local_fk_set) + if (dberr_t error= + dict_create_add_foreign_to_dictionary(table->name.m_name, fk, trx)) + return error; - return error; + return DB_SUCCESS; } diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 1a6ff572bda..74f7af216e3 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -51,9 +51,9 @@ extern uint ibuf_debug; #include "buf0buf.h" #include "data0type.h" #include "dict0boot.h" +#include "dict0load.h" #include "dict0crea.h" #include "dict0mem.h" -#include "dict0priv.h" #include "dict0stats.h" #include "fts0fts.h" #include "fts0types.h" @@ -80,6 +80,15 @@ extern uint ibuf_debug; /** the dictionary system */ dict_sys_t dict_sys; +/** System table names; @see dict_system_id_t */ +const span<const char> dict_sys_t::SYS_TABLE[]= +{ + {C_STRING_WITH_LEN("SYS_TABLES")},{C_STRING_WITH_LEN("SYS_INDEXES")}, + {C_STRING_WITH_LEN("SYS_COLUMNS")},{C_STRING_WITH_LEN("SYS_FIELDS")}, + {C_STRING_WITH_LEN("SYS_FOREIGN")},{C_STRING_WITH_LEN("SYS_FOREIGN_COLS")}, + {C_STRING_WITH_LEN("SYS_VIRTUAL")} +}; + /** Diagnostic message for exceeding the mutex_lock_wait() timeout */ const char dict_sys_t::fatal_msg[]= "innodb_fatal_semaphore_wait_threshold was exceeded for dict_sys.mutex. " @@ -216,7 +225,7 @@ static dict_table_t* dict_table_open_on_id_low( dict_err_ignore_t ignore_err, bool cached_only) { - dict_table_t* table = dict_sys.get_table(table_id); + dict_table_t* table = dict_sys.find_table(table_id); if (!table && !cached_only) { table = dict_load_table_on_id(table_id, ignore_err); @@ -1097,17 +1106,11 @@ dict_table_open_on_name( } ut_ad(table_name); - dict_sys.assert_locked(); + table = dict_sys.load_table({table_name, strlen(table_name)}, + ignore_err); - table = dict_table_check_if_in_cache_low(table_name); - - if (table == NULL) { - table = dict_load_table(table_name, ignore_err); - } - - ut_ad(!table || table->cached); - - if (table != NULL) { + if (table) { + ut_ad(table->cached); /* If table is encrypted or corrupted */ if (!(ignore_err & ~DICT_ERR_IGNORE_FK_NOKEY) @@ -2984,11 +2987,13 @@ dict_foreign_add_to_cache( dict_sys.assert_locked(); - for_table = dict_table_check_if_in_cache_low( - foreign->foreign_table_name_lookup); + for_table = dict_sys.find_table( + {foreign->foreign_table_name_lookup, + strlen(foreign->foreign_table_name_lookup)}); - ref_table = dict_table_check_if_in_cache_low( - foreign->referenced_table_name_lookup); + ref_table = dict_sys.find_table( + {foreign->referenced_table_name_lookup, + strlen(foreign->referenced_table_name_lookup)}); ut_a(for_table || ref_table); if (for_table) { @@ -3384,8 +3389,8 @@ dict_get_referenced_table( } /* Copy database_name, '/', table_name, '\0' */ - ref = static_cast<char*>(mem_heap_alloc( - heap, database_name_len + table_name_len + 2)); + const size_t len = database_name_len + table_name_len + 1; + ref = static_cast<char*>(mem_heap_alloc(heap, len + 1)); memcpy(ref, database_name, database_name_len); ref[database_name_len] = '/'; memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); @@ -3395,7 +3400,7 @@ dict_get_referenced_table( 2 = Store as given, compare in lower; case semi-sensitive */ if (lower_case_table_names == 2) { innobase_casedn_str(ref); - *table = dict_table_get_low(ref); + *table = dict_sys.load_table({ref, len}); memcpy(ref, database_name, database_name_len); ref[database_name_len] = '/'; memcpy(ref + database_name_len + 1, table_name, table_name_len + 1); @@ -3408,7 +3413,7 @@ dict_get_referenced_table( #else innobase_casedn_str(ref); #endif /* !_WIN32 */ - *table = dict_table_get_low(ref); + *table = dict_sys.load_table({ref, len}); } return(ref); @@ -5031,9 +5036,3 @@ dict_tf_to_row_format_string( ut_error; return(0); } - -bool dict_table_t::is_stats_table() const -{ - return !strcmp(name.m_name, TABLE_STATS_NAME) || - !strcmp(name.m_name, INDEX_STATS_NAME); -} diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index a0e8088831b..3fe0104f484 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -27,14 +27,13 @@ Created 4/24/1996 Heikki Tuuri #include "dict0load.h" -#include "mysql_version.h" +#include "log.h" #include "btr0pcur.h" #include "btr0btr.h" #include "dict0boot.h" #include "dict0crea.h" #include "dict0dict.h" #include "dict0mem.h" -#include "dict0priv.h" #include "dict0stats.h" #include "fsp0file.h" #include "fts0priv.h" @@ -45,18 +44,6 @@ Created 4/24/1996 Heikki Tuuri #include "srv0srv.h" #include "fts0opt.h" -/** Following are the InnoDB system tables. The positions in -this array are referenced by enum dict_system_table_id. */ -static const char* SYSTEM_TABLE_NAME[] = { - "SYS_TABLES", - "SYS_INDEXES", - "SYS_COLUMNS", - "SYS_FIELDS", - "SYS_FOREIGN", - "SYS_FOREIGN_COLS", - "SYS_VIRTUAL" -}; - /** Loads a table definition and also all its index definitions. Loads those foreign key constraints whose referenced table is already in @@ -71,26 +58,11 @@ key constraints are loaded into memory. @param[out] fk_tables Related table names that must also be loaded to ensure that all foreign key constraints are loaded. -@return table, NULL if does not exist; if the table is stored in an -.ibd file, but the file does not exist, then we set the -file_unreadable flag in the table object we return */ -static -dict_table_t* -dict_load_table_one( - const table_name_t& name, - dict_err_ignore_t ignore_err, - dict_names_t& fk_tables); - -/** Load a table definition from a SYS_TABLES record to dict_table_t. -Do not load any columns or indexes. -@param[in] name Table name -@param[in] rec SYS_TABLES record -@param[out,own] table table, or NULL -@return error message -@retval NULL on success */ -static const char* dict_load_table_low(const table_name_t& name, - const rec_t* rec, dict_table_t** table) - MY_ATTRIBUTE((nonnull, warn_unused_result)); +@return table, possibly with file_unreadable flag set +@retval nullptr if the table does not exist */ +static dict_table_t *dict_load_table_one(const span<const char> &name, + dict_err_ignore_t ignore_err, + dict_names_t &fk_tables); /** Load an index definition from a SYS_INDEXES record to dict_index_t. If allocate=TRUE, we will create a dict_index_t structure and fill it @@ -239,24 +211,11 @@ dict_startscan_system( btr_pcur_t* pcur, /*!< out: persistent cursor to the record */ mtr_t* mtr, /*!< in: the mini-transaction */ - dict_system_id_t system_id) /*!< in: which system table to open */ + dict_table_t* table) /*!< in: system table */ { - dict_table_t* system_table; - dict_index_t* clust_index; - const rec_t* rec; - - ut_a(system_id < SYS_NUM_SYSTEM_TABLES); - - system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]); - - clust_index = UT_LIST_GET_FIRST(system_table->indexes); - - btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF, pcur, - true, 0, mtr); - - rec = dict_getnext_system_low(pcur, mtr); - - return(rec); + btr_pcur_open_at_index_side(true, table->indexes.start, + BTR_SEARCH_LEAF, pcur, true, 0, mtr); + return dict_getnext_system_low(pcur, mtr); } /********************************************************************//** @@ -281,46 +240,6 @@ dict_getnext_system( } /********************************************************************//** -This function processes one SYS_TABLES record and populate the dict_table_t -struct for the table. -@return error message, or NULL on success */ -const char* -dict_process_sys_tables_rec_and_mtr_commit( -/*=======================================*/ - mem_heap_t* heap, /*!< in/out: temporary memory heap */ - const rec_t* rec, /*!< in: SYS_TABLES record */ - dict_table_t** table, /*!< out: dict_table_t to fill */ - bool cached, /*!< in: whether to load from cache */ - mtr_t* mtr) /*!< in/out: mini-transaction, - will be committed */ -{ - ulint len; - const char* field; - - field = (const char*) rec_get_nth_field_old( - rec, DICT_FLD__SYS_TABLES__NAME, &len); - - ut_a(!rec_get_deleted_flag(rec, 0)); - - ut_ad(mtr->memo_contains_page_flagged(rec, MTR_MEMO_PAGE_S_FIX)); - - /* Get the table name */ - table_name_t table_name(mem_heap_strdupl(heap, field, len)); - - if (cached) { - /* Commit before load the table again */ - mtr_commit(mtr); - - *table = dict_table_get_low(table_name.m_name); - return *table ? NULL : "Table not found in cache"; - } else { - const char* err = dict_load_table_low(table_name, rec, table); - mtr_commit(mtr); - return err; - } -} - -/********************************************************************//** This function parses a SYS_INDEXES record and populate a dict_index_t structure with the information from the record. For detail information about SYS_INDEXES fields, please refer to dict_boot() function. @@ -724,7 +643,7 @@ dict_sys_tables_type_to_tf(ulint type, bool not_redundant) /** Read and return 5 integer fields from a SYS_TABLES record. @param[in] rec A record of SYS_TABLES -@param[in] name Table Name, the same as SYS_TABLES.NAME +@param[in] name SYS_TABLES.NAME @param[out] table_id Pointer to the table_id for this table @param[out] space_id Pointer to the space_id for this table @param[out] n_cols Pointer to number of columns for this table. @@ -736,7 +655,7 @@ static bool dict_sys_tables_rec_read( const rec_t* rec, - const table_name_t& table_name, + const span<const char>& name, table_id_t* table_id, ulint* space_id, ulint* n_cols, @@ -850,10 +769,11 @@ dict_sys_tables_rec_read( const bool not_redundant = 0 != (*n_cols & DICT_N_COLS_COMPACT); if (!dict_sys_tables_type_valid(type, not_redundant)) { - ib::error() << "Table " << table_name << " in InnoDB" - " data dictionary contains invalid flags." - " SYS_TABLES.TYPE=" << type << - " SYS_TABLES.N_COLS=" << *n_cols; + sql_print_error("InnoDB: Table %.*s in InnoDB" + " data dictionary contains invalid flags." + " SYS_TABLES.TYPE=" ULINTPF + " SYS_TABLES.N_COLS=" ULINTPF, + name.size(), name.data(), type, *n_cols); return(false); } @@ -873,10 +793,13 @@ dict_sys_tables_rec_read( *flags2 = mach_read_from_4(field); if (!dict_tf2_is_valid(*flags, *flags2)) { - ib::error() << "Table " << table_name << " in InnoDB" - " data dictionary contains invalid flags." - " SYS_TABLES.TYPE=" << type - << " SYS_TABLES.MIX_LEN=" << *flags2; + sql_print_error("InnoDB: Table %.*s in InnoDB" + " data dictionary" + " contains invalid flags." + " SYS_TABLES.TYPE=" ULINTPF + " SYS_TABLES.MIX_LEN=" ULINTPF, + name.size(), name.data(), + type, *flags2); return(false); } @@ -901,7 +824,6 @@ static ulint dict_check_sys_tables() { ulint max_space_id = 0; btr_pcur_t pcur; - const rec_t* rec; mtr_t mtr; DBUG_ENTER("dict_check_sys_tables"); @@ -910,11 +832,9 @@ static ulint dict_check_sys_tables() mtr_start(&mtr); - for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); - rec != NULL; - mtr.commit(), mtr.start(), - rec = dict_getnext_system(&pcur, &mtr)) { - const byte* field; + for (const rec_t *rec = dict_startscan_system(&pcur, &mtr, + dict_sys.sys_tables); + rec; rec = dict_getnext_system(&pcur, &mtr)) { ulint len; table_id_t table_id; ulint space_id; @@ -924,39 +844,40 @@ static ulint dict_check_sys_tables() /* If a table record is not useable, ignore it and continue on to the next record. Error messages were logged. */ - if (dict_sys_tables_rec_check(rec) != NULL) { + if (dict_sys_tables_rec_check(rec)) { continue; } /* Copy the table name from rec */ - field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_TABLES__NAME, &len); + const char *field = reinterpret_cast<const char*>( + rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLES__NAME, + &len)); + + if (len == UNIV_SQL_NULL + || dict_table_t::is_garbage_name(field, len)) { + /* This table will be dropped by + dict_table_t::drop_garbage(). + We do not care if the file exists. */ + continue; + } - table_name_t table_name(mem_strdupl((char*) field, len)); DBUG_PRINT("dict_check_sys_tables", - ("name: %p, '%s'", table_name.m_name, - table_name.m_name)); + ("name: %*.s", static_cast<int>(len), field)); + + const span<const char> name{field, len}; - if (!dict_sys_tables_rec_read(rec, table_name, - &table_id, &space_id, + if (!dict_sys_tables_rec_read(rec, name, &table_id, &space_id, &n_cols, &flags, &flags2) || space_id == TRX_SYS_SPACE) { -next: - ut_free(table_name.m_name); continue; } - if (strstr(table_name.m_name, "/" TEMP_FILE_PREFIX_INNODB)) { - /* This table will be dropped by - row_mysql_drop_garbage_tables(). - We do not care if the file exists. */ - goto next; - } - if (flags2 & DICT_TF2_DISCARDED) { - ib::info() << "Ignoring tablespace for " << table_name - << " because the DISCARD flag is set ."; - goto next; + sql_print_information("InnoDB: Ignoring tablespace" + " for %.*s because " + "the DISCARD flag is set", + static_cast<int>(len), field); + continue; } /* For tables or partitions using .ibd files, the flag @@ -968,10 +889,10 @@ next: will otherwise ignore the flag. */ if (fil_space_for_table_exists_in_mem(space_id, flags)) { - goto next; + continue; } - char* filepath = fil_make_filepath(nullptr, table_name, + char* filepath = fil_make_filepath(nullptr, name, IBD, false); /* Check that the .ibd file exists. */ @@ -979,16 +900,17 @@ next: false, FIL_TYPE_TABLESPACE, space_id, dict_tf_to_fsp_flags(flags), - table_name, filepath)) { - ib::warn() << "Ignoring tablespace for " - << table_name - << " because it could not be opened."; + name, filepath)) { + sql_print_warning("InnoDB: Ignoring tablespace for" + " %.*s because it" + " could not be opened.", + static_cast<int>(name.size()), + name.data()); } max_space_id = ut_max(max_space_id, space_id); ut_free(filepath); - goto next; } mtr_commit(&mtr); @@ -1307,8 +1229,6 @@ dict_load_columns( mem_heap_t* heap) /*!< in/out: memory heap for temporary storage */ { - dict_table_t* sys_columns; - dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; @@ -1322,13 +1242,12 @@ dict_load_columns( mtr_start(&mtr); - sys_columns = dict_table_get_low("SYS_COLUMNS"); - sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); - ut_ad(!dict_table_is_comp(sys_columns)); + dict_index_t* sys_index = dict_sys.sys_columns->indexes.start; + ut_ad(!dict_sys.sys_columns->not_redundant()); - ut_ad(name_of_col_is(sys_columns, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_columns, sys_index, DICT_FLD__SYS_COLUMNS__NAME, "NAME")); - ut_ad(name_of_col_is(sys_columns, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_columns, sys_index, DICT_FLD__SYS_COLUMNS__PREC, "PREC")); tuple = dtuple_create(heap, 1); @@ -1423,7 +1342,6 @@ dict_load_virtual_one_col( dict_v_col_t* v_col, mem_heap_t* heap) { - dict_table_t* sys_virtual; dict_index_t* sys_virtual_index; btr_pcur_t pcur; dtuple_t* tuple; @@ -1442,11 +1360,10 @@ dict_load_virtual_one_col( mtr_start(&mtr); - sys_virtual = dict_table_get_low("SYS_VIRTUAL"); - sys_virtual_index = UT_LIST_GET_FIRST(sys_virtual->indexes); - ut_ad(!dict_table_is_comp(sys_virtual)); + sys_virtual_index = dict_sys.sys_virtual->indexes.start; + ut_ad(!dict_sys.sys_virtual->not_redundant()); - ut_ad(name_of_col_is(sys_virtual, sys_virtual_index, + ut_ad(name_of_col_is(dict_sys.sys_virtual, sys_virtual_index, DICT_FLD__SYS_VIRTUAL__POS, "POS")); tuple = dtuple_create(heap, 2); @@ -1656,8 +1573,6 @@ dict_load_fields( dict_index_t* index, /*!< in/out: index whose fields to load */ mem_heap_t* heap) /*!< in: memory heap for temporary storage */ { - dict_table_t* sys_fields; - dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; @@ -1671,10 +1586,9 @@ dict_load_fields( mtr_start(&mtr); - sys_fields = dict_table_get_low("SYS_FIELDS"); - sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); - ut_ad(!dict_table_is_comp(sys_fields)); - ut_ad(name_of_col_is(sys_fields, sys_index, + dict_index_t* sys_index = dict_sys.sys_fields->indexes.start; + ut_ad(!dict_sys.sys_fields->not_redundant()); + ut_ad(name_of_col_is(dict_sys.sys_fields, sys_index, DICT_FLD__SYS_FIELDS__COL_NAME, "COL_NAME")); tuple = dtuple_create(heap, 1); @@ -1889,7 +1803,6 @@ dict_load_indexes( /*!< in: error to be ignored when loading the index definition */ { - dict_table_t* sys_indexes; dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; @@ -1903,12 +1816,11 @@ dict_load_indexes( mtr_start(&mtr); - sys_indexes = dict_table_get_low("SYS_INDEXES"); - sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); - ut_ad(!dict_table_is_comp(sys_indexes)); - ut_ad(name_of_col_is(sys_indexes, sys_index, + sys_index = dict_sys.sys_indexes->indexes.start; + ut_ad(!dict_sys.sys_indexes->not_redundant()); + ut_ad(name_of_col_is(dict_sys.sys_indexes, sys_index, DICT_FLD__SYS_INDEXES__NAME, "NAME")); - ut_ad(name_of_col_is(sys_indexes, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_indexes, sys_index, DICT_FLD__SYS_INDEXES__PAGE_NO, "PAGE_NO")); tuple = dtuple_create(heap, 1); @@ -2156,11 +2068,11 @@ func_exit: Do not load any columns or indexes. @param[in] name Table name @param[in] rec SYS_TABLES record -@param[out,own] table table, or NULL +@param[out,own] table table, or nullptr @return error message -@retval NULL on success */ -static const char* dict_load_table_low(const table_name_t& name, - const rec_t* rec, dict_table_t** table) +@retval nullptr on success */ +const char *dict_load_table_low(const span<const char> &name, + const rec_t *rec, dict_table_t **table) { table_id_t table_id; ulint space_id; @@ -2183,8 +2095,8 @@ static const char* dict_load_table_low(const table_name_t& name, dict_table_decode_n_col(t_num, &n_cols, &n_v_col); - *table = dict_mem_table_create( - name.m_name, NULL, n_cols + n_v_col, n_v_col, flags, flags2); + *table = dict_table_t::create(name, nullptr, n_cols + n_v_col, + n_v_col, flags, flags2); (*table)->space_id = space_id; (*table)->id = table_id; (*table)->file_unreadable = !!(flags2 & DICT_TF2_DISCARDED); @@ -2271,44 +2183,6 @@ dict_get_and_save_data_dir_path( } } -/** Loads a table definition and also all its index definitions, and also -the cluster definition if the table is a member in a cluster. Also loads -all foreign key constraints where the foreign key is in the table or where -a foreign key references columns in this table. -@param[in] name Table name in the dbname/tablename format -@param[in] ignore_err Error to be ignored when loading - table and its index definition -@return table, NULL if does not exist; if the table is stored in an -.ibd file, but the file does not exist, then we set the file_unreadable -flag in the table object we return. */ -dict_table_t* dict_load_table(const char* name, dict_err_ignore_t ignore_err) -{ - dict_names_t fk_list; - dict_table_t* result; - dict_names_t::iterator i; - - DBUG_ENTER("dict_load_table"); - DBUG_PRINT("dict_load_table", ("loading table: '%s'", name)); - - dict_sys.assert_locked(); - - result = dict_table_check_if_in_cache_low(name); - - if (!result) { - result = dict_load_table_one(const_cast<char*>(name), - ignore_err, fk_list); - while (!fk_list.empty()) { - if (!dict_table_check_if_in_cache_low(fk_list.front())) - dict_load_table_one( - const_cast<char*>(fk_list.front()), - ignore_err, fk_list); - fk_list.pop_front(); - } - } - - DBUG_RETURN(result); -} - /** Opens a tablespace for dict_load_table_one() @param[in,out] table A table that refers to the tablespace to open @param[in] ignore_err Whether to ignore an error. */ @@ -2368,12 +2242,10 @@ dict_load_tablespace( } } - /* Try to open the tablespace. We set the 2nd param (fix_dict) to - false because we do not have an x-lock on dict_sys.latch */ table->space = fil_ibd_open( true, FIL_TYPE_TABLESPACE, table->space_id, dict_tf_to_fsp_flags(table->flags), - table->name, filepath); + {table->name.m_name, strlen(table->name.m_name)}, filepath); if (!table->space) { /* We failed to find a sensible tablespace file */ @@ -2397,20 +2269,14 @@ key constraints are loaded into memory. @param[out] fk_tables Related table names that must also be loaded to ensure that all foreign key constraints are loaded. -@return table, NULL if does not exist; if the table is stored in an -.ibd file, but the file does not exist, then we set the -file_unreadable flag in the table object we return */ -static -dict_table_t* -dict_load_table_one( - const table_name_t& name, - dict_err_ignore_t ignore_err, - dict_names_t& fk_tables) +@return table, possibly with file_unreadable flag set +@retval nullptr if the table does not exist */ +static dict_table_t *dict_load_table_one(const span<const char> &name, + dict_err_ignore_t ignore_err, + dict_names_t &fk_tables) { dberr_t err; - dict_table_t* sys_tables; btr_pcur_t pcur; - dict_index_t* sys_index; dtuple_t* tuple; mem_heap_t* heap; dfield_t* dfield; @@ -2420,7 +2286,8 @@ dict_load_table_one( mtr_t mtr; DBUG_ENTER("dict_load_table_one"); - DBUG_PRINT("dict_load_table_one", ("table: %s", name.m_name)); + DBUG_PRINT("dict_load_table_one", + ("table: %.*s", name.size(), name.data())); dict_sys.assert_locked(); @@ -2428,24 +2295,23 @@ dict_load_table_one( mtr_start(&mtr); - sys_tables = dict_table_get_low("SYS_TABLES"); - sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); - ut_ad(!dict_table_is_comp(sys_tables)); - ut_ad(name_of_col_is(sys_tables, sys_index, + dict_index_t *sys_index = dict_sys.sys_tables->indexes.start; + ut_ad(!dict_sys.sys_tables->not_redundant()); + ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index, DICT_FLD__SYS_TABLES__ID, "ID")); - ut_ad(name_of_col_is(sys_tables, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index, DICT_FLD__SYS_TABLES__N_COLS, "N_COLS")); - ut_ad(name_of_col_is(sys_tables, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index, DICT_FLD__SYS_TABLES__TYPE, "TYPE")); - ut_ad(name_of_col_is(sys_tables, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index, DICT_FLD__SYS_TABLES__MIX_LEN, "MIX_LEN")); - ut_ad(name_of_col_is(sys_tables, sys_index, + ut_ad(name_of_col_is(dict_sys.sys_tables, sys_index, DICT_FLD__SYS_TABLES__SPACE, "SPACE")); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); - dfield_set_data(dfield, name.m_name, strlen(name.m_name)); + dfield_set_data(dfield, name.data(), name.size()); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, @@ -2467,9 +2333,7 @@ err_exit: rec, DICT_FLD__SYS_TABLES__NAME, &len); /* Check if the table name in record is the searched one */ - if (len != strlen(name.m_name) - || memcmp(name.m_name, field, len)) { - + if (len != name.size() || memcmp(name.data(), field, len)) { goto err_exit; } @@ -2645,6 +2509,25 @@ func_exit: DBUG_RETURN(table); } +dict_table_t *dict_sys_t::load_table(const span<const char> &name, + dict_err_ignore_t ignore) +{ + if (dict_table_t *table= find_table(name)) + return table; + dict_names_t fk_list; + dict_table_t *table= dict_load_table_one(name, ignore, fk_list); + while (!fk_list.empty()) + { + const char *f= fk_list.front(); + const span<const char> name{f, strlen(f)}; + if (!find_table(name)) + dict_load_table_one(name, ignore, fk_list); + fk_list.pop_front(); + } + + return table; +} + /***********************************************************************//** Loads a table object based on the table id. @return table; NULL if table does not exist */ @@ -2657,48 +2540,41 @@ dict_load_table_on_id( { byte id_buf[8]; btr_pcur_t pcur; - mem_heap_t* heap; - dtuple_t* tuple; - dfield_t* dfield; - dict_index_t* sys_table_ids; - dict_table_t* sys_tables; - const rec_t* rec; const byte* field; ulint len; - dict_table_t* table; mtr_t mtr; dict_sys.assert_locked(); - table = NULL; - /* NOTE that the operation of this function is protected by the dictionary mutex, and therefore no deadlocks can occur with other dictionary operations. */ - mtr_start(&mtr); + mtr.start(); /*---------------------------------------------------*/ /* Get the secondary index based on ID for table SYS_TABLES */ - sys_tables = dict_sys.sys_tables; - sys_table_ids = dict_table_get_next_index( - dict_table_get_first_index(sys_tables)); - ut_ad(!dict_table_is_comp(sys_tables)); - ut_ad(!dict_index_is_clust(sys_table_ids)); - heap = mem_heap_create(256); - - tuple = dtuple_create(heap, 1); - dfield = dtuple_get_nth_field(tuple, 0); + dict_index_t *sys_table_ids = + dict_sys.sys_tables->indexes.start->indexes.next; + + dfield_t dfield; + dtuple_t tuple{ + 0,1,1,&dfield,0,nullptr +#ifdef UNIV_DEBUG + , DATA_TUPLE_MAGIC_N +#endif + }; /* Write the table id in byte format to id_buf */ mach_write_to_8(id_buf, table_id); + dfield_set_data(&dfield, id_buf, 8); + dict_index_copy_types(&tuple, sys_table_ids, 1); - dfield_set_data(dfield, id_buf, 8); - dict_index_copy_types(tuple, sys_table_ids, 1); - - btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE, + btr_pcur_open_on_user_rec(sys_table_ids, &tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); - rec = btr_pcur_get_rec(&pcur); + + const rec_t* rec = btr_pcur_get_rec(&pcur); + dict_table_t* table = nullptr; if (page_rec_is_user_rec(rec)) { /*---------------------------------------------------*/ @@ -2727,17 +2603,15 @@ check_rec: /* Now we get the table name from the record */ field = rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLE_IDS__NAME, &len); - /* Load the table definition to memory */ - char* table_name = mem_heap_strdupl( - heap, (char*) field, len); - table = dict_load_table(table_name, ignore_err); + table = dict_sys.load_table( + {reinterpret_cast<const char*>(field), + len}, ignore_err); } } } btr_pcur_close(&pcur); - mtr_commit(&mtr); - mem_heap_free(heap); + mtr.commit(); return(table); } @@ -2778,8 +2652,6 @@ dict_load_foreign_cols( /*===================*/ dict_foreign_t* foreign)/*!< in/out: foreign constraint object */ { - dict_table_t* sys_foreign_cols; - dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; @@ -2804,10 +2676,8 @@ dict_load_foreign_cols( mtr_start(&mtr); - sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS"); - - sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes); - ut_ad(!dict_table_is_comp(sys_foreign_cols)); + dict_index_t* sys_index = dict_sys.sys_foreign_cols->indexes.start; + ut_ad(!dict_sys.sys_foreign_cols->not_redundant()); tuple = dtuple_create(foreign->heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -2918,9 +2788,7 @@ dict_load_foreign( stack. */ { dict_foreign_t* foreign; - dict_table_t* sys_foreign; btr_pcur_t pcur; - dict_index_t* sys_index; dtuple_t* tuple; mem_heap_t* heap2; dfield_t* dfield; @@ -2944,10 +2812,8 @@ dict_load_foreign( mtr_start(&mtr); - sys_foreign = dict_table_get_low("SYS_FOREIGN"); - - sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes); - ut_ad(!dict_table_is_comp(sys_foreign)); + dict_index_t* sys_index = dict_sys.sys_foreign->indexes.start; + ut_ad(!dict_sys.sys_foreign->not_redundant()); tuple = dtuple_create(heap2, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -2965,7 +2831,7 @@ dict_load_foreign( ib::error() << "Cannot load foreign constraint " << id << ": could not find the relevant record in " - << "SYS_FOREIGN"; + "SYS_FOREIGN"; btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -3033,10 +2899,12 @@ dict_load_foreign( dict_load_foreign_cols(foreign); - ref_table = dict_table_check_if_in_cache_low( - foreign->referenced_table_name_lookup); - for_table = dict_table_check_if_in_cache_low( - foreign->foreign_table_name_lookup); + ref_table = dict_sys.find_table( + {foreign->referenced_table_name_lookup, + strlen(foreign->referenced_table_name_lookup)}); + for_table = dict_sys.find_table( + {foreign->foreign_table_name_lookup, + strlen(foreign->foreign_table_name_lookup)}); if (!for_table) { /* To avoid recursively loading the tables related through @@ -3101,8 +2969,6 @@ dict_load_foreigns( btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; - dict_index_t* sec_index; - dict_table_t* sys_foreign; const rec_t* rec; const byte* field; ulint len; @@ -3113,24 +2979,21 @@ dict_load_foreigns( dict_sys.assert_locked(); - sys_foreign = dict_table_get_low("SYS_FOREIGN"); - - if (sys_foreign == NULL) { - /* No foreign keys defined yet in this database */ - - ib::info() << "No foreign key system tables in the database"; + if (!dict_sys.sys_foreign || !dict_sys.sys_foreign_cols) { + if (ignore_err & DICT_ERR_IGNORE_FK_NOKEY) { + DBUG_RETURN(DB_SUCCESS); + } + sql_print_information("InnoDB: No foreign key system tables" + " in the database"); DBUG_RETURN(DB_ERROR); } - ut_ad(!dict_table_is_comp(sys_foreign)); + ut_ad(!dict_sys.sys_foreign->not_redundant()); mtr_start(&mtr); - /* Get the secondary index based on FOR_NAME from table - SYS_FOREIGN */ - - sec_index = dict_table_get_next_index( - dict_table_get_first_index(sys_foreign)); - ut_ad(!dict_index_is_clust(sec_index)); + dict_index_t *sec_index = dict_table_get_next_index( + dict_table_get_first_index(dict_sys.sys_foreign)); + ut_ad(!strcmp(sec_index->fields[0].name, "FOR_NAME")); start_load: tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1, 0); diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index ef7bb87e635..0631bd24bc0 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -123,85 +123,73 @@ bool dict_col_t::same_encoding(uint16_t a, uint16_t b) return false; } -/** Create a table memory object. +/** Create metadata. @param name table name @param space tablespace @param n_cols total number of columns (both virtual and non-virtual) @param n_v_cols number of virtual columns @param flags table flags @param flags2 table flags2 -@return own: table object */ -dict_table_t *dict_mem_table_create(const char *name, fil_space_t *space, - ulint n_cols, ulint n_v_cols, ulint flags, - ulint flags2) +@return newly allocated table object */ +dict_table_t *dict_table_t::create(const span<const char> &name, + fil_space_t *space, + ulint n_cols, ulint n_v_cols, ulint flags, + ulint flags2) { - dict_table_t* table; - mem_heap_t* heap; - - ut_ad(name); - ut_ad(!space - || space->purpose == FIL_TYPE_TABLESPACE - || space->purpose == FIL_TYPE_TEMPORARY - || space->purpose == FIL_TYPE_IMPORT); - ut_a(dict_tf2_is_valid(flags, flags2)); - ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK)); + ut_ad(!space || space->purpose == FIL_TYPE_TABLESPACE || + space->purpose == FIL_TYPE_TEMPORARY || + space->purpose == FIL_TYPE_IMPORT); + ut_a(dict_tf2_is_valid(flags, flags2)); + ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK)); - heap = mem_heap_create(DICT_HEAP_SIZE); + mem_heap_t *heap= mem_heap_create(DICT_HEAP_SIZE); - table = static_cast<dict_table_t*>( - mem_heap_zalloc(heap, sizeof(*table))); + dict_table_t *table= static_cast<dict_table_t*> + (mem_heap_zalloc(heap, sizeof(*table))); - lock_table_lock_list_init(&table->locks); - - UT_LIST_INIT(table->indexes, &dict_index_t::indexes); + lock_table_lock_list_init(&table->locks); + UT_LIST_INIT(table->indexes, &dict_index_t::indexes); #ifdef BTR_CUR_HASH_ADAPT - UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes); + UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes); #endif /* BTR_CUR_HASH_ADAPT */ + table->heap= heap; + + ut_d(table->magic_n= DICT_TABLE_MAGIC_N); + + table->flags= static_cast<unsigned>(flags) & ((1U << DICT_TF_BITS) - 1); + table->flags2= static_cast<unsigned>(flags2) & ((1U << DICT_TF2_BITS) - 1); + table->name.m_name= mem_strdupl(name.data(), name.size()); + table->is_system_db= dict_mem_table_is_system(table->name.m_name); + table->space= space; + table->space_id= space ? space->id : ULINT_UNDEFINED; + table->n_t_cols= static_cast<unsigned>(n_cols + DATA_N_SYS_COLS) & + dict_index_t::MAX_N_FIELDS; + table->n_v_cols= static_cast<unsigned>(n_v_cols) & + dict_index_t::MAX_N_FIELDS; + table->n_cols= static_cast<unsigned>(table->n_t_cols - table->n_v_cols) & + dict_index_t::MAX_N_FIELDS; + table->cols= static_cast<dict_col_t*> + (mem_heap_alloc(heap, table->n_cols * sizeof *table->cols)); + table->v_cols= static_cast<dict_v_col_t*> + (mem_heap_alloc(heap, n_v_cols * sizeof *table->v_cols)); + for (ulint i = n_v_cols; i--; ) + new (&table->v_cols[i]) dict_v_col_t(); + table->autoinc_lock= static_cast<ib_lock_t*> + (mem_heap_alloc(heap, sizeof *table->autoinc_lock)); + /* If the table has an FTS index or we are in the process + of building one, create the table->fts */ + if (dict_table_has_fts_index(table) || + DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID | + DICT_TF2_FTS_ADD_DOC_ID)) + { + table->fts= fts_create(table); + table->fts->cache= fts_cache_create(table); + } - table->heap = heap; - - ut_d(table->magic_n = DICT_TABLE_MAGIC_N); - - table->flags = static_cast<unsigned>(flags) - & ((1U << DICT_TF_BITS) - 1); - table->flags2 = static_cast<unsigned>(flags2) - & ((1U << DICT_TF2_BITS) - 1); - table->name.m_name = mem_strdup(name); - table->is_system_db = dict_mem_table_is_system(table->name.m_name); - table->space = space; - table->space_id = space ? space->id : ULINT_UNDEFINED; - table->n_t_cols = static_cast<unsigned>(n_cols + DATA_N_SYS_COLS) - & dict_index_t::MAX_N_FIELDS; - table->n_v_cols = static_cast<unsigned>(n_v_cols) - & dict_index_t::MAX_N_FIELDS; - table->n_cols = static_cast<unsigned>( - table->n_t_cols - table->n_v_cols) - & dict_index_t::MAX_N_FIELDS; - - table->cols = static_cast<dict_col_t*>( - mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t))); - table->v_cols = static_cast<dict_v_col_t*>( - mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols))); - for (ulint i = n_v_cols; i--; ) { - new (&table->v_cols[i]) dict_v_col_t(); - } - - table->autoinc_lock = static_cast<ib_lock_t*>( - mem_heap_alloc(heap, sizeof *table->autoinc_lock)); - - /* If the table has an FTS index or we are in the process - of building one, create the table->fts */ - if (dict_table_has_fts_index(table) - || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID) - || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) { - table->fts = fts_create(table); - table->fts->cache = fts_cache_create(table); - } - - new(&table->foreign_set) dict_foreign_set(); - new(&table->referenced_set) dict_foreign_set(); + new (&table->foreign_set) dict_foreign_set(); + new (&table->referenced_set) dict_foreign_set(); - return(table); + return table; } /****************************************************************//** diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index e3a1b874d7d..e9e91f730d5 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -25,7 +25,6 @@ Created Jan 06, 2010 Vasil Dimov *******************************************************/ #include "dict0stats.h" -#include "dict0priv.h" #include "ut0ut.h" #include "ut0rnd.h" #include "dyn0buf.h" @@ -143,6 +142,20 @@ typedef ut_allocator<std::pair<const char* const, dict_index_t*> > typedef std::map<const char*, dict_index_t*, ut_strcmp_functor, index_map_t_allocator> index_map_t; +inline bool dict_table_t::is_stats_table() const +{ + return !strcmp(name.m_name, TABLE_STATS_NAME) || + !strcmp(name.m_name, INDEX_STATS_NAME); +} + +bool trx_t::has_stats_table_lock() const +{ + for (const lock_t *l : lock.table_locks) + if (l && l->un_member.tab_lock.table->is_stats_table()) + return true; + return false; +} + /*********************************************************************//** Checks whether an index should be ignored in stats manipulations: * stats fetch @@ -179,7 +192,7 @@ struct dict_col_meta_t struct dict_table_schema_t { /** table name */ - const char *table_name; + span<const char> table_name; /** table name in SQL */ const char *table_name_sql; /** number of columns */ @@ -190,7 +203,7 @@ struct dict_table_schema_t static const dict_table_schema_t table_stats_schema = { - TABLE_STATS_NAME, TABLE_STATS_NAME_PRINT, 6, + {C_STRING_WITH_LEN(TABLE_STATS_NAME)}, TABLE_STATS_NAME_PRINT, 6, { {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192}, {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597}, @@ -203,7 +216,7 @@ static const dict_table_schema_t table_stats_schema = static const dict_table_schema_t index_stats_schema = { - INDEX_STATS_NAME, INDEX_STATS_NAME_PRINT, 8, + {C_STRING_WITH_LEN(INDEX_STATS_NAME)}, INDEX_STATS_NAME_PRINT, 8, { {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192}, {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597}, @@ -327,7 +340,7 @@ dict_table_schema_check( returned */ size_t errstr_sz) /*!< in: errstr size */ { - const dict_table_t* table = dict_table_get_low(req_schema->table_name); + const dict_table_t* table= dict_sys.load_table(req_schema->table_name); if (!table) { if (req_schema == &table_stats_schema) { diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 9615ff2d096..3ffec8efe4b 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -47,6 +47,7 @@ Created 10/25/1995 Heikki Tuuri #include "buf0lru.h" #include "ibuf0ibuf.h" #include "buf0flu.h" +#include "log.h" #ifdef UNIV_LINUX # include <sys/types.h> # include <sys/sysmacros.h> @@ -2195,7 +2196,7 @@ statement to update the dictionary tables if they are incorrect. @param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY @param[in] id tablespace ID @param[in] flags expected FSP_SPACE_FLAGS -@param[in] space_name tablespace name of the datafile +@param[in] name table name If file-per-table, it is the table name in the databasename/tablename format @param[in] path_in expected filepath, usually read from dictionary @param[out] err DB_SUCCESS or error code @@ -2207,37 +2208,40 @@ fil_ibd_open( fil_type_t purpose, ulint id, ulint flags, - const table_name_t tablename, + fil_space_t::name_type name, const char* path_in, dberr_t* err) { mysql_mutex_lock(&fil_system.mutex); - if (fil_space_t* space = fil_space_get_by_id(id)) { - mysql_mutex_unlock(&fil_system.mutex); - - if (space && validate && !srv_read_only_mode) { + fil_space_t* space = fil_space_get_by_id(id); + mysql_mutex_unlock(&fil_system.mutex); + if (space) { + if (validate && !srv_read_only_mode) { fsp_flags_try_adjust(space, flags & ~FSP_FLAGS_MEM_MASK); } - return space; } - mysql_mutex_unlock(&fil_system.mutex); - Datafile df_default; /* default location */ - RemoteDatafile df_remote; /* remote location */ - ulint tablespaces_found = 0; - ulint valid_tablespaces_found = 0; + dberr_t local_err = DB_SUCCESS; /* Table flags can be ULINT_UNDEFINED if dict_tf_to_fsp_flags_failure is set. */ if (flags == ULINT_UNDEFINED) { corrupted: - if (err) *err = DB_CORRUPTION; - return NULL; + local_err = DB_CORRUPTION; +func_exit: + if (err) *err = local_err; + return space; } ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id)); + + Datafile df_default; /* default location */ + RemoteDatafile df_remote; /* remote location */ + ulint tablespaces_found = 0; + ulint valid_tablespaces_found = 0; + df_default.init(flags); df_remote.init(flags); @@ -2245,12 +2249,11 @@ corrupted: while avoiding unecessary effort. */ /* We will always look for an ibd in the default location. */ - df_default.make_filepath(nullptr, {tablename.m_name, - strlen(tablename.m_name)}, IBD); + df_default.make_filepath(nullptr, name, IBD); /* Look for a filepath embedded in an ISL where the default file would be. */ - if (df_remote.open_link_file(tablename)) { + if (df_remote.open_link_file(name)) { validate = true; if (df_remote.open_read_only(true) == DB_SUCCESS) { ut_ad(df_remote.is_open()); @@ -2314,8 +2317,10 @@ corrupted: First, bail out if no tablespace files were found. */ if (valid_tablespaces_found == 0) { os_file_get_last_error(true); - ib::error() << "Could not find a valid tablespace file for `" - << tablename << "`. " << TROUBLESHOOT_DATADICT_MSG; + sql_print_error("InnoDB: Could not find a valid tablespace" + " file for %.*s. %s", + static_cast<int>(name.size()), name.data(), + TROUBLESHOOT_DATADICT_MSG); goto corrupted; } if (!validate) { @@ -2324,22 +2329,19 @@ corrupted: /* Do not open any tablespaces if more than one tablespace with the correct space ID and flags were found. */ - if (tablespaces_found > 1) { - ib::error() << "A tablespace for `" << tablename - << "` has been found in multiple places;"; - - if (df_default.is_open()) { - ib::error() << "Default location: " - << df_default.filepath() - << ", Space ID=" << df_default.space_id() - << ", Flags=" << df_default.flags(); - } - if (df_remote.is_open()) { - ib::error() << "Remote location: " - << df_remote.filepath() - << ", Space ID=" << df_remote.space_id() - << ", Flags=" << df_remote.flags(); - } + if (df_default.is_open() && df_remote.is_open()) { + ib::error() + << "A tablespace has been found in multiple places: " + << df_default.filepath() + << "(Space ID=" << df_default.space_id() + << ", Flags=" << df_default.flags() + << ") and " + << df_remote.filepath() + << "(Space ID=" << df_remote.space_id() + << ", Flags=" << df_remote.flags() + << (valid_tablespaces_found > 1 || srv_force_recovery + ? "); will not open" + : ")"); /* Force-recovery will allow some tablespaces to be skipped by REDO if there was more than one file found. @@ -2349,9 +2351,6 @@ corrupted: recovery and there is only one good tablespace, ignore any bad tablespaces. */ if (valid_tablespaces_found > 1 || srv_force_recovery > 0) { - ib::error() << "Will not open tablespace `" - << tablename << "`"; - /* If the file is not open it cannot be valid. */ ut_ad(df_default.is_open() || !df_default.is_valid()); ut_ad(df_remote.is_open() || !df_remote.is_valid()); @@ -2363,8 +2362,8 @@ corrupted: goto corrupted; } error: - if (err) *err = DB_ERROR; - return NULL; + local_err = DB_ERROR; + goto func_exit; } /* There is only one valid tablespace found and we did @@ -2395,8 +2394,7 @@ skip_validate: first_page) : NULL; - fil_space_t* space = fil_space_t::create( - id, flags, purpose, crypt_data); + space = fil_space_t::create(id, flags, purpose, crypt_data); if (!space) { goto error; } @@ -2420,8 +2418,7 @@ skip_validate: } } - if (err) *err = DB_SUCCESS; - return space; + goto func_exit; } /** Discover the correct IBD file to open given a remote or missing @@ -2485,14 +2482,11 @@ fil_ibd_discover( case SRV_OPERATION_RESTORE: break; case SRV_OPERATION_NORMAL: - char* name = const_cast<char*>(db); - size_t len= strlen(name); - if (len <= 4 || strcmp(name + len - 4, dot_ext[IBD])) { + size_t len= strlen(db); + if (len <= 4 || strcmp(db + len - 4, dot_ext[IBD])) { break; } - name[len - 4] = '\0'; - df_rem_per.open_link_file(table_name_t{name}); - name[len - 4] = *dot_ext[IBD]; + df_rem_per.open_link_file({db, len - 4}); if (!df_rem_per.filepath()) { break; diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index 5d49d14f65c..966febd056c 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -837,7 +837,7 @@ open that file, and read the contents into m_filepath. @param name table name @return filepath() @retval nullptr if the .isl file does not exist or cannot be read */ -const char *RemoteDatafile::open_link_file(const table_name_t &name) +const char *RemoteDatafile::open_link_file(const fil_space_t::name_type name) { if (!m_link_filepath) m_link_filepath= fil_make_filepath(nullptr, name, ISL, false); diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index ac324525772..515abf94060 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -34,7 +34,6 @@ Full Text Search interface #include "fts0types.ic" #include "fts0vlc.ic" #include "fts0plugin.h" -#include "dict0priv.h" #include "dict0stats.h" #include "btr0pcur.h" @@ -1675,8 +1674,9 @@ fts_create_in_mem_aux_table( const dict_table_t* table, ulint n_cols) { - dict_table_t* new_table = dict_mem_table_create( - aux_table_name, NULL, n_cols, 0, table->flags, + dict_table_t* new_table = dict_table_t::create( + {aux_table_name,strlen(aux_table_name)}, + nullptr, n_cols, 0, table->flags, table->space_id == TRX_SYS_SPACE ? 0 : table->space_id == SRV_TMP_SPACE_ID ? DICT_TF2_TEMPORARY : DICT_TF2_USE_FILE_PER_TABLE); @@ -5645,7 +5645,8 @@ fts_valid_stopword_table( return(NULL); } - table = dict_table_get_low(stopword_table_name); + table = dict_sys.load_table( + {stopword_table_name, strlen(stopword_table_name)}); if (!table) { ib::error() << "User stopword table " << stopword_table_name diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index b815d23394f..7a83930fb1a 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -2554,7 +2554,7 @@ void fts_optimize_add_table(dict_table_t* table) } /* Make sure table with FTS index cannot be evicted */ - dict_table_prevent_eviction(table); + dict_sys.prevent_eviction(table); msg = fts_optimize_create_msg(FTS_MSG_ADD_TABLE, table); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d57c0bd4a24..2b6089c4814 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -80,7 +80,6 @@ this program; if not, write to the Free Software Foundation, Inc., #include "btr0defragment.h" #include "dict0crea.h" #include "dict0dict.h" -#include "dict0priv.h" #include "dict0stats.h" #include "dict0stats_bg.h" #include "fil0fil.h" @@ -148,7 +147,6 @@ void close_thread_tables(THD* thd); #include <sstream> #ifdef WITH_WSREP -#include "dict0priv.h" #include <mysql/service_md5.h> #include "wsrep_sst.h" #endif /* WITH_WSREP */ @@ -1277,7 +1275,7 @@ static ibool innodb_drop_database_ignore_fk(void*,void*) { return false; } struct innodb_drop_database_fk_report { /** database name, with trailing '/' */ - const st_::span<char> name; + const span<const char> name; /** whether errors were found */ bool violated; }; @@ -9798,8 +9796,11 @@ wsrep_append_foreign_key( if (referenced) { foreign->referenced_table = - dict_table_get_low( - foreign->referenced_table_name_lookup); + dict_sys.load_table( + {foreign->referenced_table_name_lookup, + strlen(foreign-> + referenced_table_name_lookup) + }); if (foreign->referenced_table) { foreign->referenced_index = dict_foreign_find_index( @@ -9811,8 +9812,10 @@ wsrep_append_foreign_key( } } else { foreign->foreign_table = - dict_table_get_low( - foreign->foreign_table_name_lookup); + dict_sys.load_table( + {foreign->foreign_table_name_lookup, + strlen(foreign-> + foreign_table_name_lookup)}); if (foreign->foreign_table) { foreign->foreign_index = @@ -10478,8 +10481,8 @@ create_table_info_t::create_table_def() const ulint actual_n_cols = n_cols + (m_flags2 & DICT_TF2_FTS && !has_doc_id_col); - table = dict_mem_table_create(m_table_name, NULL, - actual_n_cols, num_v, m_flags, m_flags2); + table = dict_table_t::create({m_table_name,table_name_len}, nullptr, + actual_n_cols, num_v, m_flags, m_flags2); /* Set the hidden doc_id column. */ if (m_flags2 & DICT_TF2_FTS) { @@ -10696,7 +10699,7 @@ err_col: "temporary table creation."); } - table->id = dict_sys.get_temporary_table_id(); + table->id = dict_sys.acquire_temporary_table_id(); ut_ad(dict_tf_get_rec_format(table->flags) != REC_FORMAT_COMPRESSED); table->space_id = SRV_TMP_SPACE_ID; @@ -12140,7 +12143,7 @@ create_table_info_t::create_foreign_keys() ut_ad(alter_info); List_iterator_fast<Key> key_it(alter_info->key_list); - dict_table_t* table = dict_table_get_low(name); + dict_table_t* table = dict_sys.find_table({name,strlen(name)}); if (!table) { ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT, create_name, "%s table %s foreign key constraint" @@ -12630,13 +12633,12 @@ int create_table_info_t::create_table(bool create_fk) if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ dict_names_t fk_tables; - err = dict_load_foreigns(m_table_name, NULL, - false, true, - DICT_ERR_IGNORE_NONE, - fk_tables); + err = dict_load_foreigns(m_table_name, NULL, false, true, + DICT_ERR_IGNORE_NONE, fk_tables); while (err == DB_SUCCESS && !fk_tables.empty()) { - dict_load_table(fk_tables.front(), - DICT_ERR_IGNORE_NONE); + dict_sys.load_table( + {fk_tables.front(), strlen(fk_tables.front())}, + DICT_ERR_IGNORE_NONE); fk_tables.pop_front(); } } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 8583a084c94..6277283b3e0 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -35,7 +35,7 @@ Smart ALTER TABLE #include "btr0sea.h" #include "dict0crea.h" #include "dict0dict.h" -#include "dict0priv.h" +#include "dict0load.h" #include "dict0stats.h" #include "dict0stats_bg.h" #include "log0log.h" @@ -56,11 +56,9 @@ Smart ALTER TABLE #include "row0sel.h" #include "ha_innodb.h" #include "ut0stage.h" -#include "span.h" #include <thread> #include <sstream> -using st_::span; /** File format constraint for ALTER TABLE */ extern ulong innodb_instant_alter_column_allowed; @@ -2054,6 +2052,12 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } + if (!dict_sys.sys_tables_exist()) { + ha_alter_info->unsupported_reason + = "missing InnoDB system tables"; + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + } + /* Only support online add foreign key constraint when check_foreigns is turned off */ if ((ha_alter_info->handler_flags & ALTER_ADD_FOREIGN_KEY) @@ -6397,9 +6401,9 @@ new_clustered_failed: DBUG_ASSERT(!add_fts_doc_id_idx || (flags2 & DICT_TF2_FTS)); - ctx->new_table = dict_mem_table_create( - new_table_name, NULL, n_cols + n_v_cols, n_v_cols, - flags, flags2); + ctx->new_table = dict_table_t::create( + {new_table_name, tablen + partlen}, nullptr, + n_cols + n_v_cols, n_v_cols, flags, flags2); /* The rebuilt indexed_table will use the renamed column names. */ @@ -6796,7 +6800,9 @@ wrong_column_name: } } - if (dict_table_get_low(ctx->new_table->name.m_name)) { + if (dict_sys.find_table( + {ctx->new_table->name.m_name, + strlen(ctx->new_table->name.m_name)})) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), ctx->new_table->name.m_name); goto new_clustered_failed; @@ -9731,17 +9737,14 @@ innobase_update_foreign_cache( /* For complete loading of foreign keys, all associated tables must also be loaded. */ while (err == DB_SUCCESS && !fk_tables.empty()) { - dict_table_t* table = dict_load_table( - fk_tables.front(), DICT_ERR_IGNORE_NONE); - - if (table == NULL) { + const char *f = fk_tables.front(); + if (!dict_sys.load_table({f, strlen(f)})) { err = DB_TABLE_NOT_FOUND; ib::error() - << "Failed to load table '" - << table_name_t(const_cast<char*> - (fk_tables.front())) - << "' which has a foreign key constraint with" - << " table '" << user_table->name << "'."; + << "Failed to load table " + << table_name_t(const_cast<char*>(f)) + << " which has a foreign key constraint with" + << user_table->name; break; } diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index edf2acfa068..fc719557e4f 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -4820,6 +4820,41 @@ i_s_dict_fill_sys_tables( DBUG_RETURN(0); } + +/** Convert one SYS_TABLES record to dict_table_t. +@param pcur persistent cursor position on SYS_TABLES record +@param rec record to read from (nullptr=use the dict_sys cache) +@param table the converted dict_table_t +@return error message +@retval nullptr on success */ +static const char *i_s_sys_tables_rec(const btr_pcur_t &pcur, const rec_t *rec, + dict_table_t **table) +{ + static_assert(DICT_FLD__SYS_TABLES__NAME == 0, "compatibility"); + size_t len; + if (rec_get_1byte_offs_flag(pcur.old_rec)) + { + len= rec_1_get_field_end_info(pcur.old_rec, 0); + if (len & REC_1BYTE_SQL_NULL_MASK) + return "corrupted SYS_TABLES.NAME"; + } + else + { + len= rec_2_get_field_end_info(pcur.old_rec, 0); + static_assert(REC_2BYTE_EXTERN_MASK == 16384, "compatibility"); + if (len >= REC_2BYTE_EXTERN_MASK) + return "corrupted SYS_TABLES.NAME"; + } + + const span<const char>name{reinterpret_cast<const char*>(pcur.old_rec), len}; + + if (rec) + return dict_load_table_low(name, rec, table); + + *table= dict_sys.load_table(name); + return *table ? nullptr : "Table not found in cache"; +} + /*******************************************************************//** Function to go through each record in SYS_TABLES table, and fill the information_schema.innodb_sys_tables table with related table information @@ -4833,8 +4868,6 @@ i_s_sys_tables_fill_table( Item* ) /*!< in: condition (not used) */ { btr_pcur_t pcur; - const rec_t* rec; - mem_heap_t* heap; mtr_t mtr; DBUG_ENTER("i_s_sys_tables_fill_table"); @@ -4845,21 +4878,23 @@ i_s_sys_tables_fill_table( DBUG_RETURN(0); } - heap = mem_heap_create(1000); dict_sys.mutex_lock(); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); + for (const rec_t *rec = dict_startscan_system(&pcur, &mtr, + dict_sys.sys_tables); + rec; rec = dict_getnext_system(&pcur, &mtr)) { + if (rec_get_deleted_flag(rec, 0)) { + continue; + } - while (rec) { const char* err_msg; dict_table_t* table_rec; /* Create and populate a dict_table_t structure with information from SYS_TABLES row */ - err_msg = dict_process_sys_tables_rec_and_mtr_commit( - heap, rec, &table_rec, false, &mtr); - + err_msg = i_s_sys_tables_rec(pcur, rec, &table_rec); + mtr.commit(); dict_sys.mutex_unlock(); if (!err_msg) { @@ -4875,17 +4910,13 @@ i_s_sys_tables_fill_table( dict_mem_table_free(table_rec); } - mem_heap_empty(heap); - /* Get the next record */ dict_sys.mutex_lock(); - mtr_start(&mtr); - rec = dict_getnext_system(&pcur, &mtr); + mtr.start(); } - mtr_commit(&mtr); + mtr.commit(); dict_sys.mutex_unlock(); - mem_heap_free(heap); DBUG_RETURN(0); } @@ -5078,7 +5109,6 @@ i_s_sys_tables_fill_table_stats( { btr_pcur_t pcur; const rec_t* rec; - mem_heap_t* heap; mtr_t mtr; DBUG_ENTER("i_s_sys_tables_fill_table_stats"); @@ -5089,30 +5119,24 @@ i_s_sys_tables_fill_table_stats( DBUG_RETURN(0); } - heap = mem_heap_create(1000); dict_sys.freeze(); dict_sys.mutex_lock(); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_tables); while (rec) { const char* err_msg; dict_table_t* table_rec; + mtr.commit(); /* Fetch the dict_table_t structure corresponding to this SYS_TABLES record */ - err_msg = dict_process_sys_tables_rec_and_mtr_commit( - heap, rec, &table_rec, true, &mtr); + err_msg = i_s_sys_tables_rec(pcur, nullptr, &table_rec); ulint ref_count = table_rec ? table_rec->get_ref_count() : 0; dict_sys.mutex_unlock(); - DBUG_EXECUTE_IF("test_sys_tablestats", { - if (strcmp("test/t1", table_rec->name.m_name) == 0 ) { - DEBUG_SYNC_C("dict_table_not_protected"); - }}); - if (table_rec != NULL) { ut_ad(err_msg == NULL); i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count, @@ -5125,7 +5149,6 @@ i_s_sys_tables_fill_table_stats( } dict_sys.unfreeze(); - mem_heap_empty(heap); /* Get the next record */ dict_sys.freeze(); @@ -5138,7 +5161,6 @@ i_s_sys_tables_fill_table_stats( mtr_commit(&mtr); dict_sys.mutex_unlock(); dict_sys.unfreeze(); - mem_heap_free(heap); DBUG_RETURN(0); } @@ -5335,7 +5357,7 @@ i_s_sys_indexes_fill_table( mtr_start(&mtr); /* Start scan the SYS_INDEXES table */ - rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_indexes); /* Process each record in the table */ while (rec) { @@ -5553,7 +5575,7 @@ i_s_sys_columns_fill_table( dict_sys.mutex_lock(); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_columns); while (rec) { const char* err_msg; @@ -5739,14 +5761,14 @@ i_s_sys_virtual_fill_table( RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); /* deny access to user without PROCESS_ACL privilege */ - if (check_global_access(thd, PROCESS_ACL)) { + if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_virtual) { DBUG_RETURN(0); } dict_sys.mutex_lock(); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_VIRTUAL); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_virtual); while (rec) { const char* err_msg; @@ -5936,7 +5958,7 @@ i_s_sys_fields_fill_table( the next index. This is used to calculate prefix length */ last_id = 0; - rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_fields); while (rec) { ulint pos; @@ -6127,8 +6149,7 @@ i_s_sys_foreign_fill_table( RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); /* deny access to user without PROCESS_ACL privilege */ - if (check_global_access(thd, PROCESS_ACL)) { - + if (check_global_access(thd, PROCESS_ACL) || !dict_sys.sys_foreign) { DBUG_RETURN(0); } @@ -6136,7 +6157,7 @@ i_s_sys_foreign_fill_table( dict_sys.mutex_lock(); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign); while (rec) { const char* err_msg; @@ -6320,7 +6341,8 @@ i_s_sys_foreign_cols_fill_table( RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name.str); /* deny access to user without PROCESS_ACL privilege */ - if (check_global_access(thd, PROCESS_ACL)) { + if (check_global_access(thd, PROCESS_ACL) + || !dict_sys.sys_foreign_cols) { DBUG_RETURN(0); } @@ -6328,7 +6350,7 @@ i_s_sys_foreign_cols_fill_table( dict_sys.mutex_lock(); mtr_start(&mtr); - rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS); + rec = dict_startscan_system(&pcur, &mtr, dict_sys.sys_foreign_cols); while (rec) { const char* err_msg; diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index d357011bf22..178f94684f2 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -455,8 +455,9 @@ ibuf_init_at_db_start(void) mtr.commit(); ibuf.index = dict_mem_index_create( - dict_mem_table_create("innodb_change_buffer", - fil_system.sys_space, 1, 0, 0, 0), + dict_table_t::create( + {C_STRING_WITH_LEN("innodb_change_buffer")}, + fil_system.sys_space, 1, 0, 0, 0), "CLUST_IND", DICT_CLUSTERED | DICT_IBUF, 1); ibuf.index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID; @@ -1266,8 +1267,9 @@ ibuf_dummy_index_create( dict_table_t* table; dict_index_t* index; - table = dict_mem_table_create("IBUF_DUMMY", NULL, n, 0, - comp ? DICT_TF_COMPACT : 0, 0); + table = dict_table_t::create({C_STRING_WITH_LEN("IBUF_DUMMY")}, + nullptr, n, 0, + comp ? DICT_TF_COMPACT : 0, 0); index = dict_mem_index_create(table, "IBUF_DUMMY", 0, n); diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index d53c8f7ac33..59c18fde8f2 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -117,15 +117,6 @@ dict_create_index_tree_in_mem( dict_index_t* index, /*!< in/out: index */ const trx_t* trx); /*!< in: InnoDB transaction handle */ -/****************************************************************//** -Creates the foreign key constraints system tables inside InnoDB -at server bootstrap or server start if they are not found or are -not of the right form. -@return DB_SUCCESS or error code */ -dberr_t -dict_create_or_check_foreign_constraint_tables(void); -/*================================================*/ - /********************************************************************//** Generate a foreign key constraint name when it was not named by the user. A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER, @@ -171,13 +162,6 @@ dict_foreigns_has_s_base_col( const dict_foreign_set& local_fk_set, const dict_table_t* table); -/** Creates the virtual column system tables inside InnoDB -at server bootstrap or server start if they are not found or are -not of the right form. -@return DB_SUCCESS or error code */ -dberr_t -dict_create_or_check_sys_virtual(); - /********************************************************************//** Add a foreign key definition to the data dictionary tables. @return error code or DB_SUCCESS */ diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 67f5ad9ada8..73008b7560a 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -1373,23 +1373,48 @@ class dict_sys_t FIXME: merge the mutex and the latch, once MDEV-23484 has been fixed */ mysql_mutex_t mutex; public: - hash_table_t table_hash; /*!< hash table of the tables, based - on name */ - /** hash table of persistent table IDs */ - hash_table_t table_id_hash; - dict_table_t* sys_tables; /*!< SYS_TABLES table */ - dict_table_t* sys_columns; /*!< SYS_COLUMNS table */ - dict_table_t* sys_indexes; /*!< SYS_INDEXES table */ - dict_table_t* sys_fields; /*!< SYS_FIELDS table */ - dict_table_t* sys_virtual; /*!< SYS_VIRTUAL table */ - - /*=============================*/ - UT_LIST_BASE_NODE_T(dict_table_t) - table_LRU; /*!< List of tables that can be evicted - from the cache */ - UT_LIST_BASE_NODE_T(dict_table_t) - table_non_LRU; /*!< List of tables that can't be - evicted from the cache */ + /** Indexes of SYS_TABLE[] */ + enum + { + SYS_TABLES= 0, + SYS_INDEXES, + SYS_COLUMNS, + SYS_FIELDS, + SYS_FOREIGN, + SYS_FOREIGN_COLS, + SYS_VIRTUAL + }; + /** System table names */ + static const span<const char> SYS_TABLE[]; + + /** all tables (persistent and temporary), hashed by name */ + hash_table_t table_hash; + /** hash table of persistent table IDs */ + hash_table_t table_id_hash; + + /** the SYS_TABLES table */ + dict_table_t *sys_tables; + /** the SYS_COLUMNS table */ + dict_table_t *sys_columns; + /** the SYS_INDEXES table */ + dict_table_t *sys_indexes; + /** the SYS_FIELDS table */ + dict_table_t *sys_fields; + /** the SYS_FOREIGN table */ + dict_table_t *sys_foreign; + /** the SYS_FOREIGN_COLS table */ + dict_table_t *sys_foreign_cols; + /** the SYS_VIRTUAL table */ + dict_table_t *sys_virtual; + + /** @return whether all non-hard-coded system tables exist */ + bool sys_tables_exist() const + { return UNIV_LIKELY(sys_foreign && sys_foreign_cols && sys_virtual); } + + /** list of persistent tables that can be evicted */ + UT_LIST_BASE_NODE_T(dict_table_t) table_LRU; + /** list of persistent tables that cannot be evicted */ + UT_LIST_BASE_NODE_T(dict_table_t) table_non_LRU; private: bool m_initialised= false; @@ -1418,46 +1443,47 @@ public: row_id= ut_uint64_align_up(id, ROW_ID_WRITE_MARGIN) + ROW_ID_WRITE_MARGIN; } - /** @return a new temporary table ID */ - table_id_t get_temporary_table_id() { - return temp_table_id.fetch_add(1, std::memory_order_relaxed); - } + /** @return a new temporary table ID */ + table_id_t acquire_temporary_table_id() + { + return temp_table_id.fetch_add(1, std::memory_order_relaxed); + } - /** Look up a temporary table. - @param id temporary table ID - @return temporary table - @retval NULL if the table does not exist - (should only happen during the rollback of CREATE...SELECT) */ - dict_table_t* get_temporary_table(table_id_t id) - { - mysql_mutex_assert_owner(&mutex); - dict_table_t* table; - ulint fold = ut_fold_ull(id); - HASH_SEARCH(id_hash, &temp_id_hash, fold, dict_table_t*, table, - ut_ad(table->cached), table->id == id); - if (UNIV_LIKELY(table != NULL)) { - DBUG_ASSERT(table->is_temporary()); - DBUG_ASSERT(table->id >= DICT_HDR_FIRST_ID); - table->acquire(); - } - return table; - } + /** Look up a temporary table. + @param id temporary table ID + @return temporary table + @retval nullptr if the table does not exist + (should only happen during the rollback of CREATE...SELECT) */ + dict_table_t *acquire_temporary_table(table_id_t id) + { + mysql_mutex_assert_owner(&mutex); + dict_table_t *table; + ulint fold = ut_fold_ull(id); + HASH_SEARCH(id_hash, &temp_id_hash, fold, dict_table_t*, table, + ut_ad(table->cached), table->id == id); + if (UNIV_LIKELY(table != nullptr)) + { + DBUG_ASSERT(table->is_temporary()); + DBUG_ASSERT(table->id >= DICT_HDR_FIRST_ID); + table->acquire(); + } + return table; + } - /** Look up a persistent table. - @param id table ID - @return table - @retval NULL if not cached */ - dict_table_t* get_table(table_id_t id) - { - mysql_mutex_assert_owner(&mutex); - dict_table_t* table; - ulint fold = ut_fold_ull(id); - HASH_SEARCH(id_hash, &table_id_hash, fold, dict_table_t*, - table, - ut_ad(table->cached), table->id == id); - DBUG_ASSERT(!table || !table->is_temporary()); - return table; - } + /** Look up a persistent table. + @param id table ID + @return table + @retval nullptr if not cached */ + dict_table_t *find_table(table_id_t id) + { + mysql_mutex_assert_owner(&mutex); + dict_table_t *table; + ulint fold = ut_fold_ull(id); + HASH_SEARCH(id_hash, &table_id_hash, fold, dict_table_t*, table, + ut_ad(table->cached), table->id == id); + DBUG_ASSERT(!table || !table->is_temporary()); + return table; + } bool is_initialised() const { return m_initialised; } @@ -1480,14 +1506,13 @@ public: #ifdef UNIV_DEBUG /** Find a table */ - template <bool in_lru> bool find(dict_table_t* table) + template <bool in_lru> bool find(const dict_table_t *table) { ut_ad(table); ut_ad(table->can_be_evicted == in_lru); mysql_mutex_assert_owner(&mutex); - for (const dict_table_t* t = UT_LIST_GET_FIRST(in_lru - ? table_LRU : table_non_LRU); - t; t = UT_LIST_GET_NEXT(table_LRU, t)) + for (const dict_table_t* t= in_lru ? table_LRU.start : table_non_LRU.start; + t; t = UT_LIST_GET_NEXT(table_LRU, t)) { if (t == table) return true; ut_ad(t->can_be_evicted == in_lru); @@ -1495,25 +1520,25 @@ public: return false; } /** Find a table */ - bool find(dict_table_t* table) + bool find(const dict_table_t *table) { return table->can_be_evicted ? find<true>(table) : find<false>(table); } #endif /** Move a table to the non-LRU list from the LRU list. */ - void prevent_eviction(dict_table_t* table) + void prevent_eviction(dict_table_t *table) { ut_ad(find(table)); if (table->can_be_evicted) { - table->can_be_evicted = FALSE; + table->can_be_evicted= false; UT_LIST_REMOVE(table_LRU, table); UT_LIST_ADD_LAST(table_non_LRU, table); } } /** Acquire a reference to a cached table. */ - inline void acquire(dict_table_t* table); + inline void acquire(dict_table_t *table); /** Assert that the mutex is locked */ void assert_locked() const { mysql_mutex_assert_owner(&mutex); } @@ -1573,8 +1598,8 @@ public: + (sizeof(dict_col_t) + sizeof(dict_field_t)) * 10 + sizeof(dict_field_t) * 5 /* total number of key fields */ + 200; /* arbitrary, covering names and overhead */ - size += (table_hash.n_cells + table_id_hash.n_cells - + temp_id_hash.n_cells) * sizeof(hash_cell_t); + size += (table_hash.n_cells + table_id_hash.n_cells + + temp_id_hash.n_cells) * sizeof(hash_cell_t); return size; } @@ -1582,12 +1607,43 @@ public: @param half whether to consider half the tables only (instead of all) @return number of tables evicted */ ulint evict_table_LRU(bool half); + + /** Look up a table in the dictionary cache. + @param name table name + @return table handle + @retval nullptr if not found */ + dict_table_t *find_table(const span<const char> &name) const + { + assert_locked(); + for (dict_table_t *table= static_cast<dict_table_t*> + (HASH_GET_FIRST(&table_hash, table_hash.calc_hash + (ut_fold_binary(reinterpret_cast<const byte*> + (name.data()), name.size())))); + table; table= table->name_hash) + if (strlen(table->name.m_name) == name.size() && + !memcmp(table->name.m_name, name.data(), name.size())) + return table; + return nullptr; + } + + /** Look up or load a table definition + @param name table name + @param ignore errors to ignore when loading the table definition + @return table handle + @retval nullptr if not found */ + dict_table_t *load_table(const span<const char> &name, + dict_err_ignore_t ignore= DICT_ERR_IGNORE_NONE); + + /** Attempt to load the system tables on startup + @return whether any discrepancy with the expected definition was found */ + bool load_sys_tables(); + /** Create or check system tables on startup */ + dberr_t create_or_check_sys_tables(); }; /** the data dictionary cache */ extern dict_sys_t dict_sys; -#define dict_table_prevent_eviction(table) dict_sys.prevent_eviction(table) #define dict_sys_lock() dict_sys.lock(SRW_LOCK_CALL) #define dict_sys_unlock() dict_sys.unlock() diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index 645dbc12c80..591dd30f211 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -39,20 +39,6 @@ Created 4/24/1996 Heikki Tuuri /** A stack of table names related through foreign key constraints */ typedef std::deque<const char*, ut_allocator<const char*> > dict_names_t; -/** enum that defines all system table IDs. @see SYSTEM_TABLE_NAME[] */ -enum dict_system_id_t { - SYS_TABLES = 0, - SYS_INDEXES, - SYS_COLUMNS, - SYS_FIELDS, - SYS_FOREIGN, - SYS_FOREIGN_COLS, - SYS_VIRTUAL, - - /* This must be last item. Defines the number of system tables. */ - SYS_NUM_SYSTEM_TABLES -}; - /** Check each tablespace found in the data dictionary. Then look at each table defined in SYS_TABLES that has a space_id > 0 to find all the file-per-table tablespaces. @@ -74,18 +60,6 @@ dict_get_and_save_data_dir_path( dict_table_t* table, bool dict_mutex_own); -/** Loads a table definition and also all its index definitions, and also -the cluster definition if the table is a member in a cluster. Also loads -all foreign key constraints where the foreign key is in the table or where -a foreign key references columns in this table. -@param[in] name Table name in the dbname/tablename format -@param[in] ignore_err Error to be ignored when loading - table and its index definition -@return table, NULL if does not exist; if the table is stored in an -.ibd file, but the file does not exist, then we set the file_unreadable -flag in the table object we return. */ -dict_table_t* dict_load_table(const char* name, dict_err_ignore_t ignore_err); - /***********************************************************************//** Loads a table object based on the table id. @return table; NULL if table does not exist */ @@ -140,7 +114,7 @@ dict_startscan_system( btr_pcur_t* pcur, /*!< out: persistent cursor to the record */ mtr_t* mtr, /*!< in: the mini-transaction */ - dict_system_id_t system_id); /*!< in: which system table to open */ + dict_table_t* table); /*!< in: system table */ /********************************************************************//** This function get the next system table record as we scan the table. @return the record if found, NULL if end of scan. */ @@ -150,19 +124,18 @@ dict_getnext_system( btr_pcur_t* pcur, /*!< in/out: persistent cursor to the record */ mtr_t* mtr); /*!< in: the mini-transaction */ -/********************************************************************//** -This function processes one SYS_TABLES record and populate the dict_table_t -struct for the table. -@return error message, or NULL on success */ -const char* -dict_process_sys_tables_rec_and_mtr_commit( -/*=======================================*/ - mem_heap_t* heap, /*!< in: temporary memory heap */ - const rec_t* rec, /*!< in: SYS_TABLES record */ - dict_table_t** table, /*!< out: dict_table_t to fill */ - bool cached, /*!< in: whether to load from cache */ - mtr_t* mtr); /*!< in/out: mini-transaction, - will be committed */ + +/** Load a table definition from a SYS_TABLES record to dict_table_t. +Do not load any columns or indexes. +@param[in] name Table name +@param[in] rec SYS_TABLES record +@param[out,own] table table, or nullptr +@return error message +@retval nullptr on success */ +const char *dict_load_table_low(const span<const char> &name, + const rec_t *rec, dict_table_t **table) + MY_ATTRIBUTE((nonnull, warn_unused_result)); + /********************************************************************//** This function parses a SYS_INDEXES record and populate a dict_index_t structure with the information from the record. For detail information diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 71554e116eb..867826f92d6 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -28,10 +28,10 @@ Created 1/8/1996 Heikki Tuuri #ifndef dict0mem_h #define dict0mem_h +#include "dict0types.h" #include "data0type.h" #include "mem0mem.h" #include "row0types.h" -#include "rem0types.h" #include "btr0types.h" #include "lock0types.h" #include "que0types.h" @@ -298,17 +298,6 @@ parent table will fail, and user has to drop excessive foreign constraint before proceeds. */ #define FK_MAX_CASCADE_DEL 15 -/** Create a table memory object. -@param name table name -@param space tablespace -@param n_cols total number of columns (both virtual and non-virtual) -@param n_v_cols number of virtual columns -@param flags table flags -@param flags2 table flags2 -@return own: table object */ -dict_table_t *dict_mem_table_create(const char *name, fil_space_t *space, - ulint n_cols, ulint n_v_cols, ulint flags, - ulint flags2); /****************************************************************/ /** Free a table memory object. */ void @@ -1816,7 +1805,7 @@ typedef enum { } dict_frm_t; /** Data structure for a database table. Most fields will be -initialized to 0, NULL or FALSE in dict_mem_table_create(). */ +zero-initialized in dict_table_t::create(). */ struct dict_table_t { /** Get reference count. @@ -2435,10 +2424,24 @@ public: return false; } - /** Check whether the table name is same as mysql/innodb_stats_table - or mysql/innodb_index_stats. - @return true if the table name is same as stats table */ - bool is_stats_table() const; + /** @return whether the name is + mysql.innodb_index_stats or mysql.innodb_table_stats */ + inline bool is_stats_table() const; + + /** Create metadata. + @param name table name + @param space tablespace + @param n_cols total number of columns (both virtual and non-virtual) + @param n_v_cols number of virtual columns + @param flags table flags + @param flags2 table flags2 + @return newly allocated table object */ + static dict_table_t *create(const span<const char> &name, fil_space_t *space, + ulint n_cols, ulint n_v_cols, ulint flags, + ulint flags2); + + /** @return whether SYS_TABLES.NAME is for a '#sql-ib' table */ + static bool is_garbage_name(const void *data, size_t size); }; inline void dict_index_t::set_modified(mtr_t& mtr) const diff --git a/storage/innobase/include/dict0priv.h b/storage/innobase/include/dict0priv.h deleted file mode 100644 index 3f2792054e0..00000000000 --- a/storage/innobase/include/dict0priv.h +++ /dev/null @@ -1,50 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/dict0priv.h -Data dictionary private functions - -Created Fri 2 Jul 2010 13:30:38 EST - Sunny Bains -*******************************************************/ - -#ifndef dict0priv_h -#define dict0priv_h - -/**********************************************************************//** -Gets a table; loads it to the dictionary cache if necessary. A low-level -function. Note: Not to be called from outside dict0*c functions. -@return table, NULL if not found */ -UNIV_INLINE -dict_table_t* -dict_table_get_low( -/*===============*/ - const char* table_name); /*!< in: table name */ - -/**********************************************************************//** -Checks if a table is in the dictionary cache. -@return table, NULL if not found */ -UNIV_INLINE -dict_table_t* -dict_table_check_if_in_cache_low( -/*=============================*/ - const char* table_name); /*!< in: table name */ - -#include "dict0priv.ic" - -#endif /* dict0priv.h */ diff --git a/storage/innobase/include/dict0priv.ic b/storage/innobase/include/dict0priv.ic deleted file mode 100644 index 36d0ba66524..00000000000 --- a/storage/innobase/include/dict0priv.ic +++ /dev/null @@ -1,91 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2010, 2014, Oracle and/or its affiliates. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/******************************************************************//** -@file include/dict0priv.ic -Data dictionary system private include file - -Created Wed 13 Oct 2010 16:10:14 EST Sunny Bains -***********************************************************************/ - -#include "dict0dict.h" -#include "dict0load.h" - -/**********************************************************************//** -Gets a table; loads it to the dictionary cache if necessary. A low-level -function. -@return table, NULL if not found */ -UNIV_INLINE -dict_table_t* -dict_table_get_low( -/*===============*/ - const char* table_name) /*!< in: table name */ -{ - dict_table_t* table; - - ut_ad(table_name); - dict_sys.assert_locked(); - - table = dict_table_check_if_in_cache_low(table_name); - - if (table && table->corrupted) { - ib::error error; - error << "Table " << table->name << "is corrupted"; - if (srv_load_corrupted) { - error << ", but innodb_force_load_corrupted is set"; - } else { - return(NULL); - } - } - - if (table == NULL) { - table = dict_load_table(table_name, DICT_ERR_IGNORE_NONE); - } - - ut_ad(!table || table->cached); - - return(table); -} - -/**********************************************************************//** -Checks if a table is in the dictionary cache. -@return table, NULL if not found */ -UNIV_INLINE -dict_table_t* -dict_table_check_if_in_cache_low( -/*=============================*/ - const char* table_name) /*!< in: table name */ -{ - dict_table_t* table; - ulint table_fold; - - DBUG_ENTER("dict_table_check_if_in_cache_low"); - DBUG_PRINT("dict_table_check_if_in_cache_low", - ("table: '%s'", table_name)); - - ut_ad(table_name); - dict_sys.assert_locked(); - - /* Look for the table name in the hash table */ - table_fold = ut_fold_string(table_name); - - HASH_SEARCH(name_hash, &dict_sys.table_hash, table_fold, - dict_table_t*, table, ut_ad(table->cached), - !strcmp(table->name.m_name, table_name)); - DBUG_RETURN(table); -} diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h index 24bc84d776c..cfd0ff98912 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -28,8 +28,11 @@ Created 1/8/1996 Heikki Tuuri #define dict0types_h #include "univ.i" +#include "span.h" #include <rem0types.h> +using st_::span; + struct dict_col_t; struct dict_field_t; struct dict_index_t; diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 85ee8ce6f99..c59b4c54265 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -39,7 +39,6 @@ Created 10/25/1995 Heikki Tuuri #include "log0recv.h" #include "dict0types.h" #include "ilist.h" -#include "span.h" #include <set> #include <mutex> @@ -1621,7 +1620,7 @@ char* fil_make_filepath(const char *path, const fil_space_t::name_type &name, ib_extention ext, bool trim_name); char *fil_make_filepath(const char* path, const table_name_t name, - ib_extention ext, bool trim_name); + ib_extention suffix, bool strip_name); /** Create a tablespace file. @param[in] space_id Tablespace ID @@ -1677,7 +1676,7 @@ statement to update the dictionary tables if they are incorrect. @param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY @param[in] id tablespace ID @param[in] flags expected FSP_SPACE_FLAGS -@param[in] tablename table name +@param[in] name table name If file-per-table, it is the table name in the databasename/tablename format @param[in] path_in expected filepath, usually read from dictionary @param[out] err DB_SUCCESS or error code @@ -1689,7 +1688,7 @@ fil_ibd_open( fil_type_t purpose, ulint id, ulint flags, - const table_name_t tablename, + fil_space_t::name_type name, const char* path_in, dberr_t* err = NULL) MY_ATTRIBUTE((warn_unused_result)); diff --git a/storage/innobase/include/fsp0file.h b/storage/innobase/include/fsp0file.h index 3ec56c75476..8c11d61c5aa 100644 --- a/storage/innobase/include/fsp0file.h +++ b/storage/innobase/include/fsp0file.h @@ -501,7 +501,7 @@ public: @param name table name @return filepath() @retval nullptr if the .isl file does not exist or cannot be read */ - const char* open_link_file(const table_name_t& name); + const char* open_link_file(const fil_space_t::name_type name); /** Delete an InnoDB Symbolic Link (ISL) file. */ void delete_link_file(void); diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 6674d2f4fbc..0b4590b67bc 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -377,25 +377,17 @@ row_create_index_for_mysql( fil_encryption_t mode, /*!< in: encryption mode */ uint32_t key_id) /*!< in: encryption key_id */ MY_ATTRIBUTE((warn_unused_result)); -/*********************************************************************//** -The master thread in srv0srv.cc calls this regularly to drop tables which -we must drop in background after queries to them have ended. Such lazy -dropping of tables is needed in ALTER TABLE on Unix. + +/** The master task calls this regularly to drop tables which +we must drop in background after queries to them have ended. @return how many tables dropped + remaining tables in list */ -ulint -row_drop_tables_for_mysql_in_background(void); -/*=========================================*/ -/*********************************************************************//** -Get the background drop list length. NOTE: the caller must own the kernel -mutex! -@return how many tables in list */ -ulint -row_get_background_drop_list_len_low(void); -/*======================================*/ +ulint row_drop_tables_for_mysql_in_background(); + +/** @return number of tables in the background drop list */ +ulint row_get_background_drop_list_len_low(); /** Drop garbage tables during recovery. */ -void -row_mysql_drop_garbage_tables(); +void row_mysql_drop_garbage_tables(); /*********************************************************************//** Sets an exclusive lock on a table. diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 813afd4763a..a570f3cb5e0 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -964,7 +964,7 @@ public: } /** @return whether the table has lock on - mysql.innodb_table_stats and mysql.innodb_index_stats */ + mysql.innodb_table_stats or mysql.innodb_index_stats */ bool has_stats_table_lock() const; /** Free the memory to trx_pools */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 2b75a6bf8d7..058f8386434 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -3857,7 +3857,7 @@ released: LockMutexGuard g{SRW_LOCK_CALL}; for (const table_id_t id : to_evict) { - if (dict_table_t *table= dict_sys.get_table(id)) + if (dict_table_t *table= dict_sys.find_table(id)) if (!table->get_ref_count() && !UT_LIST_GET_LEN(table->locks)) dict_sys.remove(table, true); } diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index 09ac48bce0f..ca73ede64ae 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -1652,8 +1652,8 @@ page_zip_fields_decode( return(NULL); } - table = dict_mem_table_create("ZIP_DUMMY", NULL, n, 0, - DICT_TF_COMPACT, 0); + table = dict_table_t::create({C_STRING_WITH_LEN("ZIP_DUMMY")}, + nullptr, n, 0, DICT_TF_COMPACT, 0); index = dict_mem_index_create(table, "ZIP_DUMMY", 0, n); index->n_uniq = static_cast<unsigned>(n) & dict_index_t::MAX_N_FIELDS; /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */ diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc index 5ec408342a8..abd8dd9b26a 100644 --- a/storage/innobase/pars/pars0pars.cc +++ b/storage/innobase/pars/pars0pars.cc @@ -1783,8 +1783,9 @@ pars_create_table( n_cols = que_node_list_get_len(column_defs); - table = dict_mem_table_create( - table_sym->name, NULL, n_cols, 0, flags, flags2); + table = dict_table_t::create( + {table_sym->name, strlen(table_sym->name)}, + nullptr, n_cols, 0, flags, flags2); mem_heap_t* heap = pars_sym_tab_global->heap; column = column_defs; diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 5ad7de3fb8c..0d8b2007f07 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -4091,7 +4091,10 @@ row_import_for_mysql( ut_ad(!DICT_TF_HAS_DATA_DIR(table->flags) || table->data_dir_path); const char *data_dir_path = DICT_TF_HAS_DATA_DIR(table->flags) ? table->data_dir_path : nullptr; - filepath = fil_make_filepath(data_dir_path, table->name, IBD, + fil_space_t::name_type name{ + table->name.m_name, strlen(table->name.m_name)}; + + filepath = fil_make_filepath(data_dir_path, name, IBD, data_dir_path != nullptr); DBUG_EXECUTE_IF( @@ -4116,7 +4119,7 @@ row_import_for_mysql( table->space = fil_ibd_open( true, FIL_TYPE_IMPORT, table->space_id, - fsp_flags, table->name, filepath, &err); + fsp_flags, name, filepath, &err); ut_ad((table->space == NULL) == (err != DB_SUCCESS)); DBUG_EXECUTE_IF("ib_import_open_tablespace_failure", diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 8b12714d3d4..77dffca290c 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -36,7 +36,6 @@ Created 9/17/2000 Heikki Tuuri #include "dict0crea.h" #include "dict0dict.h" #include "dict0load.h" -#include "dict0priv.h" #include "dict0stats.h" #include "dict0stats_bg.h" #include "dict0defrag_bg.h" @@ -2321,9 +2320,8 @@ row_create_table_for_mysql( ib::error() << "Trying to create a MySQL system table " << table->name << " of type InnoDB. MySQL system" " tables must be of the MyISAM type!"; -#ifndef DBUG_OFF + err_exit: -#endif /* !DBUG_OFF */ dict_mem_table_free(table); trx->op_info = ""; @@ -2331,6 +2329,11 @@ err_exit: return(DB_ERROR); } + if (!dict_sys.sys_tables_exist()) { + ib::error() << "Some InnoDB system tables are missing"; + goto err_exit; + } + trx_start_if_not_started_xa(trx, true); heap = mem_heap_create(512); @@ -2622,10 +2625,8 @@ row_get_background_drop_list_len_low(void) } /** Drop garbage tables during recovery. */ -void -row_mysql_drop_garbage_tables() +void row_mysql_drop_garbage_tables() { - mem_heap_t* heap = mem_heap_create(FN_REFLEN); btr_pcur_t pcur; mtr_t mtr; trx_t* trx = trx_create(); @@ -2641,7 +2642,6 @@ row_mysql_drop_garbage_tables() const rec_t* rec; const byte* field; ulint len; - const char* table_name; btr_pcur_move_to_next_user_rec(&pcur, &mtr); @@ -2655,38 +2655,37 @@ row_mysql_drop_garbage_tables() } field = rec_get_nth_field_old(rec, 0/*NAME*/, &len); - if (len == UNIV_SQL_NULL || len == 0) { + if (len == UNIV_SQL_NULL) { /* Corrupted SYS_TABLES.NAME */ continue; } - table_name = mem_heap_strdupl( - heap, - reinterpret_cast<const char*>(field), len); - if (strstr(table_name, "/" TEMP_FILE_PREFIX_INNODB)) { - btr_pcur_store_position(&pcur, &mtr); - btr_pcur_commit_specify_mtr(&pcur, &mtr); - - if (dict_load_table(table_name, - DICT_ERR_IGNORE_DROP)) { - row_drop_table_for_mysql(table_name, trx, - SQLCOM_DROP_TABLE); - trx_commit_for_mysql(trx); - } + if (!dict_table_t::is_garbage_name(field, len)) { + continue; + } - mtr.start(); - btr_pcur_restore_position(BTR_SEARCH_LEAF, - &pcur, &mtr); + btr_pcur_store_position(&pcur, &mtr); + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + const span<const char> name = { + reinterpret_cast<const char*>(pcur.old_rec), len + }; + if (dict_sys.load_table(name, DICT_ERR_IGNORE_DROP)) { + char* table_name = mem_strdupl(name.data(), len); + row_drop_table_for_mysql(table_name, trx, + SQLCOM_DROP_TABLE); + ut_free(table_name); + trx_commit_for_mysql(trx); } - mem_heap_empty(heap); + mtr.start(); + btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); } btr_pcur_close(&pcur); mtr.commit(); row_mysql_unlock_data_dictionary(trx); trx->free(); - mem_heap_free(heap); } /*********************************************************************//** @@ -3160,38 +3159,6 @@ row_drop_ancillary_fts_tables( return(DB_SUCCESS); } -/** Drop a table from the memory cache as part of dropping a table. -@param[in] tablename A copy of table->name. Used when table == null -@param[in,out] table Table cache entry -@param[in,out] trx Transaction handle -@return error code or DB_SUCCESS */ -UNIV_INLINE -dberr_t -row_drop_table_from_cache( - const char* tablename, - dict_table_t* table, - trx_t* trx) -{ - dberr_t err = DB_SUCCESS; - ut_ad(!table->is_temporary()); - - /* Remove the pointer to this table object from the list - of modified tables by the transaction because the object - is going to be destroyed below. */ - trx->mod_tables.erase(table); - - dict_sys.remove(table); - - if (dict_load_table(tablename, DICT_ERR_IGNORE_FK_NOKEY)) { - ib::error() << "Not able to remove table " - << ut_get_name(trx, tablename) - << " from the dictionary cache!"; - err = DB_ERROR; - } - - return(err); -} - /** Drop a table for MySQL. If the data dictionary was not already locked by the transaction, the transaction will be committed. Otherwise, the data dictionary @@ -3331,7 +3298,7 @@ row_drop_table_for_mysql( } } - dict_table_prevent_eviction(table); + dict_sys.prevent_eviction(table); dict_table_close(table, TRUE, FALSE); /* Check if the table is referenced by foreign key constraints from @@ -3475,10 +3442,8 @@ defer: pars_info_add_str_literal(info, "name", name); - if (sqlcom != SQLCOM_TRUNCATE - && strchr(name, '/') - && dict_table_get_low("SYS_FOREIGN") - && dict_table_get_low("SYS_FOREIGN_COLS")) { + if (sqlcom != SQLCOM_TRUNCATE && strchr(name, '/') + && dict_sys.sys_foreign && dict_sys.sys_foreign_cols) { err = que_eval_sql( info, "PROCEDURE DROP_FOREIGN_PROC () IS\n" @@ -3507,7 +3472,7 @@ defer: } } else { do_drop: - if (dict_table_get_low("SYS_VIRTUAL")) { + if (dict_sys.sys_virtual) { err = que_eval_sql( info, "PROCEDURE DROP_VIRTUAL_PROC () IS\n" @@ -3588,12 +3553,8 @@ do_drop: IBD, table->data_dir_path != nullptr); - /* Free the dict_table_t object. */ - err = row_drop_table_from_cache(tablename, table, trx); - if (err != DB_SUCCESS) { - ut_free(filepath); - break; - } + trx->mod_tables.erase(table); + dict_sys.remove(table); /* Do not attempt to drop known-to-be-missing tablespaces, nor the system tablespace. */ @@ -4136,8 +4097,8 @@ row_rename_table_for_mysql( dict_mem_table_fill_foreign_vcol_set(table); while (!fk_tables.empty()) { - dict_load_table(fk_tables.front(), - DICT_ERR_IGNORE_NONE); + const char *f = fk_tables.front(); + dict_sys.load_table({f, strlen(f)}); fk_tables.pop_front(); } diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 9a598718616..51a5d30e7d3 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -428,10 +428,10 @@ static bool row_undo_ins_parse_undo_rec(undo_node_t* node, bool dict_locked) DICT_TABLE_OP_NORMAL); } else if (!dict_locked) { dict_sys.mutex_lock(); - node->table = dict_sys.get_temporary_table(table_id); + node->table = dict_sys.acquire_temporary_table(table_id); dict_sys.mutex_unlock(); } else { - node->table = dict_sys.get_temporary_table(table_id); + node->table = dict_sys.acquire_temporary_table(table_id); } if (!node->table) { diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index d363e82f1f1..5452229d9cb 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -1256,10 +1256,10 @@ static bool row_undo_mod_parse_undo_rec(undo_node_t* node, bool dict_locked) DICT_TABLE_OP_NORMAL); } else if (!dict_locked) { dict_sys.mutex_lock(); - node->table = dict_sys.get_temporary_table(table_id); + node->table = dict_sys.acquire_temporary_table(table_id); dict_sys.mutex_unlock(); } else { - node->table = dict_sys.get_temporary_table(table_id); + node->table = dict_sys.acquire_temporary_table(table_id); } if (!node->table) { diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 524964e0124..6d4412f5c42 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1454,6 +1454,7 @@ file_checked: if (srv_operation == SRV_OPERATION_RESTORE) { break; } + dict_sys.load_sys_tables(); trx_lists_init_at_db_start(); break; case SRV_OPERATION_RESTORE_DELTA: @@ -1796,11 +1797,7 @@ skip_monitors: } } - /* Create the SYS_FOREIGN and SYS_FOREIGN_COLS system tables */ - err = dict_create_or_check_foreign_constraint_tables(); - if (err == DB_SUCCESS) { - err = dict_create_or_check_sys_virtual(); - } + err = dict_sys.create_or_check_sys_tables(); switch (err) { case DB_SUCCESS: break; diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index fbf78393021..4ccacaff683 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -703,7 +703,6 @@ static my_bool trx_rollback_recovered_callback(rw_trx_hash_element_t *element, return 0; } - /** Rollback any incomplete transactions which were encountered in crash recovery. diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 0ebb4a493b8..353273ac046 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -2214,16 +2214,3 @@ trx_set_rw_mode( trx->read_view.set_creator_trx_id(trx->id); } } - -bool trx_t::has_stats_table_lock() const -{ - for (lock_list::const_iterator it= lock.table_locks.begin(), - end= lock.table_locks.end(); it != end; ++it) - { - const lock_t *lock= *it; - if (lock && lock->un_member.tab_lock.table->is_stats_table()) - return true; - } - - return false; -} |