From 49e2c8f0a6fefdeac50925f758090d6bd099768d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 20 May 2021 14:58:25 +0300 Subject: [PATCH] MDEV-25743: Unnecessary copying of table names in InnoDB dictionary Many InnoDB data dictionary cache operations require that the table name be copied so that it will be NUL terminated. (For example, SYS_TABLES.NAME is not guaranteed to be NUL-terminated.) dict_table_t::is_garbage_name(): Check if a name belongs to the background drop table queue. dict_check_if_system_table_exists(): Remove. dict_sys_t::load_sys_tables(): Load the non-hard-coded system tables SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_VIRTUAL on startup. dict_sys_t::create_or_check_sys_tables(): Replaces dict_create_or_check_foreign_constraint_tables() and dict_create_or_check_sys_virtual(). dict_sys_t::load_table(): Replaces dict_table_get_low() and dict_load_table(). dict_sys_t::find_table(): Renamed from get_table(). dict_sys_t::sys_tables_exist(): Check whether all the non-hard-coded tables SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_VIRTUAL exist. trx_t::has_stats_table_lock(): Moved to dict0stats.cc. Some error messages will now report table names in the internal databasename/tablename format, instead of `databasename`.`tablename`. --- extra/mariabackup/xtrabackup.cc | 8 +- mysql-test/suite/innodb/r/restart.result | 2 +- .../innodb/r/row_format_redundant.result | 2 +- mysql-test/suite/innodb/r/table_flags.result | 4 +- .../suite/innodb/r/truncate_missing.result | 2 +- .../innodb/t/alter_missing_tablespace.test | 2 +- mysql-test/suite/innodb/t/log_file_name.test | 2 +- mysql-test/suite/innodb/t/restart.test | 2 +- .../suite/innodb/t/row_format_redundant.test | 4 +- mysql-test/suite/innodb/t/table_flags.test | 8 +- .../suite/innodb/t/truncate_missing.test | 2 +- .../suite/innodb_fts/t/crash_recovery.test | 2 +- .../innodb_zip/r/wl5522_debug_zip.result | 2 +- .../suite/innodb_zip/t/wl5522_debug_zip.test | 2 +- mysql-test/suite/mariabackup/missing_ibd.test | 2 +- storage/innobase/CMakeLists.txt | 2 - storage/innobase/dict/dict0boot.cc | 180 +++---- storage/innobase/dict/dict0crea.cc | 470 ++++++++---------- storage/innobase/dict/dict0dict.cc | 51 +- storage/innobase/dict/dict0load.cc | 445 ++++++----------- storage/innobase/dict/dict0mem.cc | 118 ++--- storage/innobase/dict/dict0stats.cc | 23 +- storage/innobase/fil/fil0fil.cc | 94 ++-- storage/innobase/fsp/fsp0file.cc | 2 +- storage/innobase/fts/fts0fts.cc | 9 +- storage/innobase/fts/fts0opt.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 36 +- storage/innobase/handler/handler0alter.cc | 35 +- storage/innobase/handler/i_s.cc | 94 ++-- storage/innobase/ibuf/ibuf0ibuf.cc | 10 +- storage/innobase/include/dict0crea.h | 16 - storage/innobase/include/dict0dict.h | 188 ++++--- storage/innobase/include/dict0load.h | 53 +- storage/innobase/include/dict0mem.h | 37 +- storage/innobase/include/dict0priv.h | 50 -- storage/innobase/include/dict0priv.ic | 91 ---- storage/innobase/include/dict0types.h | 3 + storage/innobase/include/fil0fil.h | 7 +- storage/innobase/include/fsp0file.h | 2 +- storage/innobase/include/row0mysql.h | 24 +- storage/innobase/include/trx0trx.h | 2 +- storage/innobase/lock/lock0lock.cc | 2 +- storage/innobase/page/page0zip.cc | 4 +- storage/innobase/pars/pars0pars.cc | 5 +- storage/innobase/row/row0import.cc | 7 +- storage/innobase/row/row0mysql.cc | 105 ++-- storage/innobase/row/row0uins.cc | 4 +- storage/innobase/row/row0umod.cc | 4 +- storage/innobase/srv/srv0start.cc | 7 +- storage/innobase/trx/trx0roll.cc | 1 - storage/innobase/trx/trx0trx.cc | 13 - 51 files changed, 918 insertions(+), 1324 deletions(-) delete mode 100644 storage/innobase/include/dict0priv.h delete mode 100644 storage/innobase/include/dict0priv.ic diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index a0b09d434f7fe..223f8d56ecfe0 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -71,7 +71,6 @@ Street, Fifth Floor, Boston, MA 02110-1335 USA #include -#include #include #include #include @@ -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 9bbcc3285cfcf..ea9734d5a01fb 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 0eede61b17519..f354666f64549 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 210d370aab4b3..ce71d9b022d53 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 938bd5f2213fe..1cc654f0d7e7d 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 c615c9ff537fc..bf7111509bd16 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 f6a32b93dd9c3..534c4e6984f31 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 2af0f2dd570cb..a5f2e5a42e8ce 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 e8869b886c8c2..aadbfd2b77396 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 b037e46fb4f2f..f3a2c856af242 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 c357f5bae727d..fb6bd6782378b 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 fe58ca0addf96..d5518b91590c1 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 92886ef7505ac..8708f26a65301 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 a543fc956d42f..0c9bcb6cf9d5b 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 5e34b873b0921..dc1406039e7e2 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 35a1330cbd21d..222e671a900ab 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 afe8b5ec16559..2792f71376d61 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 1d2f4f1abb185..0efc8a8990318 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 @@ uint32_t dict_drop_index_tree(btr_pcur_t *pcur, trx_t *trx, mtr_t *mtr) 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(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 @@ dict_create_index_step( 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 1a6ff572bda28..74f7af216e314 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 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(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(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 a0e8088831b34..3fe0104f48489 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 &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); } /********************************************************************//** @@ -280,46 +239,6 @@ dict_getnext_system( return(rec); } -/********************************************************************//** -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 @@ -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& 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( + 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(len), field)); + + const span 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(len), field); + continue; } /* For tables or partitions using .ibd files, the flag @@ -968,10 +889,10 @@ static ulint dict_check_sys_tables() 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 @@ static ulint dict_check_sys_tables() 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(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 @@ dict_load_indexes( 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 &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(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(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 &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 @@ dict_load_table_one( 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 @@ dict_load_table_one( DBUG_RETURN(table); } +dict_table_t *dict_sys_t::load_table(const span &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 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 @@ dict_load_table_on_id( /* 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(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 ef7bb87e635fa..0631bd24bc033 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 &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( - mem_heap_zalloc(heap, sizeof(*table))); + dict_table_t *table= static_cast + (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(flags) & ((1U << DICT_TF_BITS) - 1); + table->flags2= static_cast(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(n_cols + DATA_N_SYS_COLS) & + dict_index_t::MAX_N_FIELDS; + table->n_v_cols= static_cast(n_v_cols) & + dict_index_t::MAX_N_FIELDS; + table->n_cols= static_cast(table->n_t_cols - table->n_v_cols) & + dict_index_t::MAX_N_FIELDS; + table->cols= static_cast + (mem_heap_alloc(heap, table->n_cols * sizeof *table->cols)); + table->v_cols= static_cast + (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 + (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(flags) - & ((1U << DICT_TF_BITS) - 1); - table->flags2 = static_cast(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(n_cols + DATA_N_SYS_COLS) - & dict_index_t::MAX_N_FIELDS; - table->n_v_cols = static_cast(n_v_cols) - & dict_index_t::MAX_N_FIELDS; - table->n_cols = static_cast( - table->n_t_cols - table->n_v_cols) - & dict_index_t::MAX_N_FIELDS; - - table->cols = static_cast( - mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t))); - table->v_cols = static_cast( - 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( - 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 e3a1b874d7d3d..e9e91f730d5c9 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 > typedef std::map 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 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 9615ff2d09602..3ffec8efe4b28 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 # include @@ -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 @@ fil_ibd_open( 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 @@ fil_ibd_open( 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(name.size()), name.data(), + TROUBLESHOOT_DATADICT_MSG); goto corrupted; } if (!validate) { @@ -2324,22 +2329,19 @@ fil_ibd_open( /* 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 @@ fil_ibd_open( 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 @@ fil_ibd_open( 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 @@ fil_ibd_open( 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 @@ fil_ibd_open( } } - 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(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 5d49d14f65c0a..966febd056cd1 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 ac32452577251..515abf9406027 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 b815d23394f51..7a83930fb1a5c 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 d57c0bd4a2434..2b6089c481482 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 #ifdef WITH_WSREP -#include "dict0priv.h" #include #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 name; + const span 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 @@ create_table_info_t::create_table_def() "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_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 8583a084c94e1..6277283b3e019 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 #include -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 @@ prepare_inplace_alter_table_dict( 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 @@ prepare_inplace_alter_table_dict( } } - 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 - (fk_tables.front())) - << "' which has a foreign key constraint with" - << " table '" << user_table->name << "'."; + << "Failed to load table " + << table_name_t(const_cast(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 edf2acfa068a9..fc719557e4f38 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 spanname{reinterpret_cast(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 d357011bf22f1..178f94684f2ba 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 d53c8f7ac339e..59c18fde8f21d 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 67f5ad9ada826..73008b7560a4f 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 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 @@ class dict_sys_t 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 @@ class dict_sys_t #ifdef UNIV_DEBUG /** Find a table */ - template bool find(dict_table_t* table) + template 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 @@ class dict_sys_t return false; } /** Find a table */ - bool find(dict_table_t* table) + bool find(const dict_table_t *table) { return table->can_be_evicted ? find(table) : find(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 @@ class dict_sys_t + (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 @@ class dict_sys_t @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 &name) const + { + assert_locked(); + for (dict_table_t *table= static_cast + (HASH_GET_FIRST(&table_hash, table_hash.calc_hash + (ut_fold_binary(reinterpret_cast + (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 &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 645dbc12c80fd..591dd30f2115e 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 > 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 &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 71554e116eb07..867826f92d620 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 @@ struct dict_table_t { 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 &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 3f2792054e0c1..0000000000000 --- 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 36d0ba6652413..0000000000000 --- 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 24bc84d776cc7..cfd0ff9891205 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 +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 85ee8ce6f99e1..c59b4c5426551 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 #include @@ -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 3ec56c754763b..8c11d61c5aa48 100644 --- a/storage/innobase/include/fsp0file.h +++ b/storage/innobase/include/fsp0file.h @@ -501,7 +501,7 @@ class RemoteDatafile : public Datafile @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 6674d2f4fbca6..0b4590b67bc2a 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 813afd4763afa..a570f3cb5e080 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -964,7 +964,7 @@ struct trx_t : ilist_node<> } /** @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 2b75a6bf8d781..058f838643480 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -3857,7 +3857,7 @@ void lock_release(trx_t *trx) 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 09ac48bce0f45..ca73ede64ae51 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(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 5ec408342a8a8..abd8dd9b26ae0 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 5ad7de3fb8c2f..0d8b2007f07dd 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 8b12714d3d4c7..77dffca290c99 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 @@ row_create_table_for_mysql( 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(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 name = { + reinterpret_cast(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 @@ row_drop_table_for_mysql( 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 @@ row_drop_table_for_mysql( } } 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 @@ row_drop_table_for_mysql( 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 9a598718616a3..51a5d30e7d395 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 d363e82f1f144..5452229d9cb2a 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 524964e0124ae..6d4412f5c42d4 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1454,6 +1454,7 @@ dberr_t srv_start(bool create_new_db) 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 @@ dberr_t srv_start(bool create_new_db) } } - /* 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 fbf7839302146..4ccacaff6837e 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 0ebb4a493b82e..353273ac046e1 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; -}