From 055a3334adc004bd3a897990c2f93178e6bb5f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 28 Aug 2018 13:43:06 +0300 Subject: [PATCH 1/7] MDEV-13564 Mariabackup does not work with TRUNCATE Implement undo tablespace truncation via normal redo logging. Implement TRUNCATE TABLE as a combination of RENAME to #sql-ib name, CREATE, and DROP. Note: Orphan #sql-ib*.ibd may be left behind if MariaDB Server 10.2 is killed before the DROP operation is committed. If MariaDB Server 10.2 is killed during TRUNCATE, it is also possible that the old table was renamed to #sql-ib*.ibd but the data dictionary will refer to the table using the original name. In MariaDB Server 10.3, RENAME inside InnoDB is transactional, and #sql-* tables will be dropped on startup. So, this new TRUNCATE will be fully crash-safe in 10.3. ha_mroonga::wrapper_truncate(): Pass table options to the underlying storage engine, now that ha_innobase::truncate() will need them. rpl_slave_state::truncate_state_table(): Before truncating mysql.gtid_slave_pos, evict any cached table handles from the table definition cache, so that there will be no stale references to the old table after truncating. == TRUNCATE TABLE == WL#6501 in MySQL 5.7 introduced separate log files for implementing atomic and crash-safe TRUNCATE TABLE, instead of using the InnoDB undo and redo log. Some convoluted logic was added to the InnoDB crash recovery, and some extra synchronization (including a redo log checkpoint) was introduced to make this work. This synchronization has caused performance problems and race conditions, and the extra log files cannot be copied or applied by external backup programs. In order to support crash-upgrade from MariaDB 10.2, we will keep the logic for parsing and applying the extra log files, but we will no longer generate those files in TRUNCATE TABLE. A prerequisite for crash-safe TRUNCATE is a crash-safe RENAME TABLE (with full redo and undo logging and proper rollback). This will be implemented in MDEV-14717. ha_innobase::truncate(): Invoke RENAME, create(), delete_table(). Because RENAME cannot be fully rolled back before MariaDB 10.3 due to missing undo logging, add some explicit rename-back in case the operation fails. ha_innobase::delete(): Introduce a variant that takes sqlcom as a parameter. In TRUNCATE TABLE, we do not want to touch any FOREIGN KEY constraints. ha_innobase::create(): Add the parameters file_per_table, trx. In TRUNCATE, the new table must be created in the same transaction that renames the old table. create_table_info_t::create_table_info_t(): Add the parameters file_per_table, trx. row_drop_table_for_mysql(): Replace a bool parameter with sqlcom. row_drop_table_after_create_fail(): New function, wrapping row_drop_table_for_mysql(). dict_truncate_index_tree_in_mem(), fil_truncate_tablespace(), fil_prepare_for_truncate(), fil_reinit_space_header_for_table(), row_truncate_table_for_mysql(), TruncateLogger, row_truncate_prepare(), row_truncate_rollback(), row_truncate_complete(), row_truncate_fts(), row_truncate_update_system_tables(), row_truncate_foreign_key_checks(), row_truncate_sanity_checks(): Remove. row_upd_check_references_constraints(): Remove a check for TRUNCATE, now that the table is no longer truncated in place. The new test innodb.truncate_foreign uses DEBUG_SYNC to cover some race-condition like scenarios. The test innodb-innodb.truncate does not use any synchronization. We add a redo log subformat to indicate backup-friendly format. MariaDB 10.4 will remove support for the old TRUNCATE logging, so crash-upgrade from old 10.2 or 10.3 to 10.4 will involve limitations. == Undo tablespace truncation == MySQL 5.7 implements undo tablespace truncation. It is only possible when innodb_undo_tablespaces is set to at least 2. The logging is implemented similar to the WL#6501 TRUNCATE, that is, using separate log files and a redo log checkpoint. We can simply implement undo tablespace truncation within a single mini-transaction that reinitializes the undo log tablespace file. Unfortunately, due to the redo log format of some operations, currently, the total redo log written by undo tablespace truncation will be more than the combined size of the truncated undo tablespace. It should be acceptable to have a little more than 1 megabyte of log in a single mini-transaction. This will be fixed in MDEV-17138 in MariaDB Server 10.4. recv_sys_t: Add truncated_undo_spaces[] to remember for which undo tablespaces a MLOG_FILE_CREATE2 record was seen. namespace undo: Remove some unnecessary declarations. fil_space_t::is_being_truncated: Document that this flag now only applies to undo tablespaces. Remove some references. fil_space_t::is_stopping(): Do not refer to is_being_truncated. This check is for tablespaces of tables. Potentially used tablespaces are never truncated any more. buf_dblwr_process(): Suppress the out-of-bounds warning for undo tablespaces. fil_truncate_log(): Write a MLOG_FILE_CREATE2 with a nonzero page number (new size of the tablespace in pages) to inform crash recovery that the undo tablespace size has been reduced. fil_op_write_log(): Relax assertions, so that MLOG_FILE_CREATE2 can be written for undo tablespaces (without .ibd file suffix) for a nonzero page number. os_file_truncate(): Add the parameter allow_shrink=false so that undo tablespaces can actually be shrunk using this function. fil_name_parse(): For undo tablespace truncation, buffer MLOG_FILE_CREATE2 in truncated_undo_spaces[]. recv_read_in_area(): Avoid reading pages for which no redo log records remain buffered, after recv_addr_trim() removed them. trx_rseg_header_create(): Add a FIXME comment that we could write much less redo log. trx_undo_truncate_tablespace(): Reinitialize the undo tablespace in a single mini-transaction, which will be flushed to the redo log before the file size is trimmed. recv_addr_trim(): Discard any redo logs for pages that were logged after the new end of a file, before the truncation LSN. If the rec_list becomes empty, reduce n_addrs. After removing any affected records, actually truncate the file. recv_apply_hashed_log_recs(): Invoke recv_addr_trim() right before applying any log records. The undo tablespace files must be open at this point. buf_flush_or_remove_pages(), buf_flush_dirty_pages(), buf_LRU_flush_or_remove_pages(): Add a parameter for specifying the number of the first page to flush or remove (default 0). trx_purge_initiate_truncate(): Remove the log checkpoints, the extra logging, and some unnecessary crash points. Merge the code from trx_undo_truncate_tablespace(). First, flush all to-be-discarded pages (beyond the new end of the file), then trim the space->size to make the page allocation deterministic. At the only remaining crash injection point, flush the redo log, so that the recovery can be tested. --- extra/mariabackup/xtrabackup.cc | 1 + .../gcol/r/innodb_virtual_debug_purge.result | 6 +- .../gcol/t/innodb_virtual_debug_purge.test | 6 - .../innodb/include/innodb_wl6501_crash.inc | 416 ------ .../include/innodb_wl6501_crash_temp.inc | 98 -- mysql-test/suite/innodb/r/truncate.result | 8 + .../suite/innodb/r/truncate_debug.result | 88 -- .../suite/innodb/r/truncate_foreign.result | 58 + .../suite/innodb/r/truncate_inject.result | 114 -- .../suite/innodb/r/truncate_missing.result | 17 + .../innodb/r/truncate_purge_debug.result | 29 - .../suite/innodb/r/truncate_restart.result | 12 - mysql-test/suite/innodb/t/truncate.test | 17 + mysql-test/suite/innodb/t/truncate_debug.test | 127 -- .../suite/innodb/t/truncate_foreign.test | 68 + .../suite/innodb/t/truncate_inject.test | 97 -- .../suite/innodb/t/truncate_missing.test | 22 + .../suite/innodb/t/truncate_purge_debug.opt | 3 - .../suite/innodb/t/truncate_purge_debug.test | 49 - .../suite/innodb/t/truncate_restart.test | 16 - mysql-test/suite/innodb_fts/r/truncate.result | 31 - mysql-test/suite/innodb_fts/t/truncate.opt | 1 - mysql-test/suite/innodb_fts/t/truncate.test | 50 - .../innodb_undo/include/truncate_recover.inc | 8 - .../suite/innodb_undo/r/truncate.result | 1 + .../r/truncate_multi_client.result | 1 + .../innodb_undo/r/truncate_recover.result | 16 +- mysql-test/suite/innodb_undo/t/truncate.test | 1 + .../innodb_undo/t/truncate_multi_client.test | 1 + .../suite/innodb_undo/t/truncate_recover.test | 38 +- .../include/innodb_wl6501_scale.inc | 112 -- mysql-test/suite/innodb_zip/r/restart.result | 24 +- mysql-test/suite/innodb_zip/r/wl6501_1.result | 1202 ---------------- .../suite/innodb_zip/r/wl6501_crash_3.result | 462 ------ .../suite/innodb_zip/r/wl6501_crash_4.result | 519 ------- .../suite/innodb_zip/r/wl6501_crash_5.result | 462 ------ .../suite/innodb_zip/r/wl6501_scale_1.result | 345 ----- mysql-test/suite/innodb_zip/t/wl6501_1.test | 451 ------ .../suite/innodb_zip/t/wl6501_crash_3.test | 25 - .../suite/innodb_zip/t/wl6501_crash_4.test | 27 - .../suite/innodb_zip/t/wl6501_crash_5.test | 25 - .../suite/innodb_zip/t/wl6501_scale_1.test | 37 - .../mariabackup/truncate_during_backup.test | 1 - sql/rpl_gtid.cc | 2 + storage/innobase/buf/buf0dblwr.cc | 3 +- storage/innobase/buf/buf0lru.cc | 26 +- storage/innobase/buf/buf0rea.cc | 26 +- storage/innobase/dict/dict0crea.cc | 99 +- storage/innobase/fil/fil0crypt.cc | 6 +- storage/innobase/fil/fil0fil.cc | 185 +-- storage/innobase/fsp/fsp0fsp.cc | 1 - storage/innobase/fts/fts0fts.cc | 14 +- storage/innobase/handler/ha_innodb.cc | 242 ++-- storage/innobase/handler/ha_innodb.h | 19 +- storage/innobase/handler/handler0alter.cc | 3 +- storage/innobase/ibuf/ibuf0ibuf.cc | 2 +- storage/innobase/include/buf0lru.h | 6 +- storage/innobase/include/dict0crea.h | 8 - storage/innobase/include/fil0fil.h | 52 +- storage/innobase/include/lock0lock.h | 4 +- storage/innobase/include/log0log.h | 8 +- storage/innobase/include/log0recv.h | 9 + storage/innobase/include/os0file.h | 7 +- storage/innobase/include/row0mysql.h | 46 +- storage/innobase/include/row0trunc.h | 11 +- storage/innobase/include/trx0purge.h | 38 - storage/innobase/include/trx0undo.h | 14 +- storage/innobase/lock/lock0lock.cc | 9 +- storage/innobase/log/log0log.cc | 1 + storage/innobase/log/log0recv.cc | 99 +- storage/innobase/os/os0file.cc | 22 +- storage/innobase/row/row0ins.cc | 3 +- storage/innobase/row/row0merge.cc | 2 +- storage/innobase/row/row0mysql.cc | 139 +- storage/innobase/row/row0trunc.cc | 1270 +---------------- storage/innobase/row/row0uins.cc | 4 +- storage/innobase/row/row0umod.cc | 4 +- storage/innobase/row/row0upd.cc | 28 - storage/innobase/srv/srv0start.cc | 3 +- storage/innobase/trx/trx0purge.cc | 231 +-- storage/innobase/trx/trx0rseg.cc | 6 +- storage/innobase/trx/trx0undo.cc | 99 -- storage/mroonga/ha_mroonga.cpp | 11 +- 83 files changed, 907 insertions(+), 6947 deletions(-) delete mode 100644 mysql-test/suite/innodb/include/innodb_wl6501_crash.inc delete mode 100644 mysql-test/suite/innodb/include/innodb_wl6501_crash_temp.inc create mode 100644 mysql-test/suite/innodb/r/truncate.result delete mode 100644 mysql-test/suite/innodb/r/truncate_debug.result create mode 100644 mysql-test/suite/innodb/r/truncate_foreign.result delete mode 100644 mysql-test/suite/innodb/r/truncate_inject.result create mode 100644 mysql-test/suite/innodb/r/truncate_missing.result delete mode 100644 mysql-test/suite/innodb/r/truncate_purge_debug.result delete mode 100644 mysql-test/suite/innodb/r/truncate_restart.result create mode 100644 mysql-test/suite/innodb/t/truncate.test delete mode 100644 mysql-test/suite/innodb/t/truncate_debug.test create mode 100644 mysql-test/suite/innodb/t/truncate_foreign.test delete mode 100644 mysql-test/suite/innodb/t/truncate_inject.test create mode 100644 mysql-test/suite/innodb/t/truncate_missing.test delete mode 100644 mysql-test/suite/innodb/t/truncate_purge_debug.opt delete mode 100644 mysql-test/suite/innodb/t/truncate_purge_debug.test delete mode 100644 mysql-test/suite/innodb/t/truncate_restart.test delete mode 100644 mysql-test/suite/innodb_fts/r/truncate.result delete mode 100644 mysql-test/suite/innodb_fts/t/truncate.opt delete mode 100644 mysql-test/suite/innodb_fts/t/truncate.test delete mode 100644 mysql-test/suite/innodb_undo/include/truncate_recover.inc delete mode 100644 mysql-test/suite/innodb_zip/include/innodb_wl6501_scale.inc delete mode 100644 mysql-test/suite/innodb_zip/r/wl6501_1.result delete mode 100644 mysql-test/suite/innodb_zip/r/wl6501_crash_3.result delete mode 100644 mysql-test/suite/innodb_zip/r/wl6501_crash_4.result delete mode 100644 mysql-test/suite/innodb_zip/r/wl6501_crash_5.result delete mode 100644 mysql-test/suite/innodb_zip/r/wl6501_scale_1.result delete mode 100644 mysql-test/suite/innodb_zip/t/wl6501_1.test delete mode 100644 mysql-test/suite/innodb_zip/t/wl6501_crash_3.test delete mode 100644 mysql-test/suite/innodb_zip/t/wl6501_crash_4.test delete mode 100644 mysql-test/suite/innodb_zip/t/wl6501_crash_5.test delete mode 100644 mysql-test/suite/innodb_zip/t/wl6501_scale_1.test diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 4af5cc0d1d5..1faa10f9c7a 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4188,6 +4188,7 @@ reread_log_header: byte MY_ALIGNED(OS_FILE_LOG_BLOCK_SIZE) log_hdr[OS_FILE_LOG_BLOCK_SIZE]; memset(log_hdr, 0, sizeof log_hdr); mach_write_to_4(LOG_HEADER_FORMAT + log_hdr, log_sys->log.format); + mach_write_to_4(LOG_HEADER_SUBFORMAT + log_hdr, 1); mach_write_to_8(LOG_HEADER_START_LSN + log_hdr, checkpoint_lsn_start); strcpy(reinterpret_cast(LOG_HEADER_CREATOR + log_hdr), "Backup " MYSQL_SERVER_VERSION); diff --git a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result index 3fbc4576ece..08f8d2098f6 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_debug_purge.result @@ -191,22 +191,18 @@ connection default; COMMIT; connect truncate,localhost,root,,; REPLACE INTO t1(pk, y) SELECT pk,y FROM t1; -SET DEBUG_SYNC='row_trunc_before_dict_lock SIGNAL commit WAIT_FOR release'; TRUNCATE TABLE t1; connection prevent_purge; -SET DEBUG_SYNC='now WAIT_FOR commit'; COMMIT; SET DEBUG_SYNC='now SIGNAL purge_start'; disconnect prevent_purge; connection default; SET DEBUG_SYNC='now WAIT_FOR purge_start'; -InnoDB 1 transactions not purged -SET DEBUG_SYNC='now SIGNAL release'; +InnoDB 0 transactions not purged SET GLOBAL debug_dbug=@old_dbug; connection truncate; disconnect truncate; connection default; -InnoDB 0 transactions not purged DROP TABLE t1, t2; set debug_sync=reset; SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test index 845881a6d07..1541920d3ae 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_debug_purge.test @@ -240,21 +240,16 @@ COMMIT; connect(truncate,localhost,root,,); REPLACE INTO t1(pk, y) SELECT pk,y FROM t1; -SET DEBUG_SYNC='row_trunc_before_dict_lock SIGNAL commit WAIT_FOR release'; send TRUNCATE TABLE t1; connection prevent_purge; -SET DEBUG_SYNC='now WAIT_FOR commit'; COMMIT; SET DEBUG_SYNC='now SIGNAL purge_start'; disconnect prevent_purge; connection default; SET DEBUG_SYNC='now WAIT_FOR purge_start'; -let $wait_all_purged=1; --source ../../innodb/include/wait_all_purged.inc -let $wait_all_purged=0; -SET DEBUG_SYNC='now SIGNAL release'; SET GLOBAL debug_dbug=@old_dbug; connection truncate; @@ -262,7 +257,6 @@ reap; disconnect truncate; connection default; ---source ../../innodb/include/wait_all_purged.inc DROP TABLE t1, t2; --source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/include/innodb_wl6501_crash.inc b/mysql-test/suite/innodb/include/innodb_wl6501_crash.inc deleted file mode 100644 index 93eca7ec060..00000000000 --- a/mysql-test/suite/innodb/include/innodb_wl6501_crash.inc +++ /dev/null @@ -1,416 +0,0 @@ -# -# WL#6501: make truncate table atomic -# - ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/big_test.inc - -# Valgrind would complain about memory leaks when we crash on purpose. ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - -# suppress expected warnings. -call mtr.add_suppression("The file '.*' already exists though the corresponding table did not exist in the InnoDB data dictionary"); -call mtr.add_suppression("Cannot create file '.*'"); -call mtr.add_suppression("InnoDB: Error number 17 means 'File exists'"); - -################################################################################ -# -# Will test following scenarios: -# 1. Hit crash point while writing redo log. -# 2. Hit crash point on completion of redo log write. -# 3. Hit crash point while dropping indexes. -# 4. Hit crash point on completing drop of all indexes before creation of index -# is commenced. -# 5. Hit crash point while creating indexes. -# 6. Hit crash point after data is updated to system-table and in-memory dict. -# 7. Hit crash point before/after log checkpoint is done. -# -################################################################################ - -#----------------------------------------------------------------------------- -# -# create test-bed -# -let $per_table = `select @@innodb_file_per_table`; - -eval set global innodb_file_per_table = on; -let $WL6501_TMP_DIR = `select @@tmpdir`; -let $WL6501_DATA_DIR = `select @@datadir`; -let SEARCH_FILE = $MYSQLTEST_VARDIR/log/my_restart.err; - -#----------------------------------------------------------------------------- -# -# 1. Hit crash point while writing redo log. -# ---echo "1. Hit crash point while writing redo log." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine=innodb row_format=$wl6501_row_fmt - key_block_size=$wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_while_writing_redo_log"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -select * from t where f < 2.5; -drop table t; - -#----------------------------------------------------------------------------- -# -# 2. Hit crash point on completion of redo log write. -# ---echo "2. Hit crash point on completion of redo log write." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_after_redo_log_write_complete"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; - -#----------------------------------------------------------------------------- -# -# 3. Hit crash point while dropping indexes. -# ---echo "3. Hit crash point while dropping indexes." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_drop_of_clust_index"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; -# -# -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_drop_of_uniq_index"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -# -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; -# -# -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_drop_of_sec_index"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; - -#----------------------------------------------------------------------------- -# -# 4. Hit crash point on completing drop of all indexes before creation of index -# is commenced. -# ---echo "4. Hit crash point on completing drop of all indexes before creation" ---echo " of index is commenced." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_drop_reinit_done_create_to_start"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; - -#----------------------------------------------------------------------------- -# -# 5. Hit crash point while creating indexes. -# ---echo "5. Hit crash point while creating indexes." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_create_of_clust_index"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; -# -# -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_create_of_uniq_index"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; -# -# -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_create_of_sec_index"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; - -#----------------------------------------------------------------------------- -# -# 6. Hit crash point after data is updated to system-table and in-memory dict. -# ---echo "6. Hit crash point after data is updated to system-table and" ---echo " in-memory dict." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_updating_dict_sys_info"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; - -#----------------------------------------------------------------------------- -# -# 7. Hit crash point before/after log checkpoint is done. -# ---echo "7. Hit crash point before/after log checkpoint is done." -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_before_log_removal"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t where f < 2.5; -drop table t; -# -# -use test; -eval set global innodb_file_per_table = $wl6501_file_per_table; -SET innodb_strict_mode=OFF; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_after_truncate_done"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; -select * from t; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -select * from t where f < 2.5; -drop table t; - - -#----------------------------------------------------------------------------- -# -# remove test-bed -# -eval set global innodb_file_per_table = $per_table; diff --git a/mysql-test/suite/innodb/include/innodb_wl6501_crash_temp.inc b/mysql-test/suite/innodb/include/innodb_wl6501_crash_temp.inc deleted file mode 100644 index edec93b875c..00000000000 --- a/mysql-test/suite/innodb/include/innodb_wl6501_crash_temp.inc +++ /dev/null @@ -1,98 +0,0 @@ -# -# WL#6501: make truncate table atomic -# - ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/big_test.inc - -# Valgrind would complain about memory leaks when we crash on purpose. ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - -# suppress expected warnings -call mtr.add_suppression("does not exist in the InnoDB internal"); - -################################################################################ -# -# Will test following scenarios: -# 1. Hit crash point on completing drop of all indexes before creation of index -# is commenced. -# 2. Hit crash point after data is updated to system-table and in-memory dict. -# -################################################################################ - -#----------------------------------------------------------------------------- -# -# create test-bed -# -let $per_table = `select @@innodb_file_per_table`; - -eval set global innodb_file_per_table = on; -let $WL6501_TMP_DIR = `select @@tmpdir`; -let $WL6501_DATA_DIR = `select @@datadir`; -let SEARCH_FILE = $MYSQLTEST_VARDIR/log/my_restart.err; - -#----------------------------------------------------------------------------- -# -# 1. Hit crash point on completing drop of all indexes before creation of index -# is commenced. -# ---echo "1. Hit crash point on completing drop of all indexes before creation" ---echo " of index is commenced." -eval set global innodb_file_per_table = $wl6501_file_per_table; -set innodb_strict_mode=off; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_drop_reinit_done_create_to_start"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; - -#----------------------------------------------------------------------------- -# -# 2. Hit crash point after data is updated to system-table and in-memory dict. -# ---echo "2. Hit crash point after data is updated to system-table and" ---echo " in-memory dict." -eval set global innodb_file_per_table = $wl6501_file_per_table; -set innodb_strict_mode=off; ---disable_warnings -eval create $wl6501_temp table t ( - i int, f float, c char, - primary key pk(i), unique findex(f), index ck(c)) - engine = innodb row_format = $wl6501_row_fmt - key_block_size = $wl6501_kbs; ---enable_warnings -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -check table t; -# -set session debug = "+d,ib_trunc_crash_on_updating_dict_sys_info"; ---source include/expect_crash.inc ---error 2013 -truncate table t; -# ---source include/start_mysqld.inc -check table t; - -#----------------------------------------------------------------------------- -# -# remove test-bed -# -eval set global innodb_file_per_table = $per_table; diff --git a/mysql-test/suite/innodb/r/truncate.result b/mysql-test/suite/innodb/r/truncate.result new file mode 100644 index 00000000000..3ade1e7f8de --- /dev/null +++ b/mysql-test/suite/innodb/r/truncate.result @@ -0,0 +1,8 @@ +CREATE TABLE t (a SERIAL) ENGINE=InnoDB; +connect dml,localhost,root; +select * from t; +a +connection default; +TRUNCATE TABLE t; +disconnect dml; +DROP TABLE t; diff --git a/mysql-test/suite/innodb/r/truncate_debug.result b/mysql-test/suite/innodb/r/truncate_debug.result deleted file mode 100644 index c04b83dbbe8..00000000000 --- a/mysql-test/suite/innodb/r/truncate_debug.result +++ /dev/null @@ -1,88 +0,0 @@ -# -# Bug #23070734 CONCURRENT TRUNCATE TABLES CAUSE STALLS -# -SET @ahi= @@global.innodb_adaptive_hash_index; -SET GLOBAL innodb_adaptive_hash_index=OFF; -SET GLOBAL innodb_adaptive_hash_index=ON; -Test_1 :- Check if DDL operations are possible on -table being truncated. Also check if -DDL operations on other tables succeed. -create table t1 (f1 int,f2 int,key(f2),f3 int) engine=innodb; -create index idx1 on t1(f3); -create table t2 (f1 int,f2 int,key(f2),f3 int) engine=innodb; -create table t3 (f1 int,f2 int,key(f2)) engine=innodb; -insert into t1 values (10,20,30),(30,40,50),(50,60,70); -insert into t1 select * from t1; -insert into t1 select * from t1; -insert into t1 select * from t1; -insert into t2 values (10,20,30),(30,40,50),(50,60,70); -insert into t2 select * from t2; -insert into t2 select * from t2; -insert into t2 select * from t2; -insert into t3 values (10,20),(30,40),(50,50); -insert into t3 select * from t3; -insert into t3 select * from t3; -SET session lock_wait_timeout = 1; -connect con1,localhost,root,,; -SET DEBUG_SYNC= 'buffer_pool_scan SIGNAL started WAIT_FOR finish_scan'; -truncate table t1; -connection default; -SET DEBUG_SYNC= 'now WAIT_FOR started'; -Check Analyze table. Gives lock time out error. -analyze table t1; -Table Op Msg_type Msg_text -test.t1 analyze Error Lock wait timeout exceeded; try restarting transaction -test.t1 analyze status Operation failed -Check if we can turn off auto recalculation. -alter table t1 STATS_AUTO_RECALC=0; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Check if we can turn off persistent stats on the table -alter table t1 STATS_PERSISTENT=0; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Check if DML is possible on table being truncated -insert into t1 values (10,89,99); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Check if DDL is possible on table being truncated -alter table t1 add column f4 int; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -check if table can be created with the same name -create table t1 (bd int) engine=innodb; -Got one of the listed errors -check if index can be created on table being truncated -create index idx1 on t1(f1); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Check if DROP of table is possible during truncate -drop table t1; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Check if select is possible during truncate -select * from t1; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -select * from t2 where t2.f1=t1.f1; -ERROR 42S22: Unknown column 't1.f1' in 'where clause' -Check concurrent truncate operation on table; -truncate table t1; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Check concurrent selects and inserts on the other table -insert into t3 values (10,20),(30,40),(50,50); -select * from t3 where f1=40; -f1 f2 -Concurrent truncate on other tables -truncate table t2; -Concurrent alters on the other tables -alter table t2 add column f4 int; -check if index can be created on the other table -create index idx1 on t2(f3); -Check if we can turn off persistent stats off entire instance -SET GLOBAL innodb_stats_persistent=off; -connect con2,localhost,root,,; -set global innodb_adaptive_hash_index=off; -connection default; -SET DEBUG_SYNC= 'now SIGNAL finish_scan'; -connection con1; -disconnect con1; -connection con2; -disconnect con2; -connection default; -SET DEBUG_SYNC= 'RESET'; -SET GLOBAL innodb_adaptive_hash_index=@ahi; -drop table t1,t2,t3; diff --git a/mysql-test/suite/innodb/r/truncate_foreign.result b/mysql-test/suite/innodb/r/truncate_foreign.result new file mode 100644 index 00000000000..bcf5b16aa83 --- /dev/null +++ b/mysql-test/suite/innodb/r/truncate_foreign.result @@ -0,0 +1,58 @@ +CREATE TABLE parent (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO parent SET a=1; +CREATE TABLE child (a INT PRIMARY KEY, FOREIGN KEY (a) REFERENCES parent(a) +ON UPDATE CASCADE) +ENGINE=InnoDB; +INSERT INTO child SET a=1; +TRUNCATE TABLE parent; +ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`a`) REFERENCES `test`.`parent` (`a`)) +TRUNCATE TABLE child; +INSERT INTO child SET a=1; +UPDATE parent SET a=2; +SELECT * FROM child; +a +2 +connect dml,localhost,root; +SET DEBUG_SYNC='foreign_constraint_update_cascade SIGNAL fk WAIT_FOR go'; +UPDATE parent SET a=3; +connection default; +SET DEBUG_SYNC='now WAIT_FOR fk'; +SET lock_wait_timeout=1; +TRUNCATE TABLE child; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SET DEBUG_SYNC='now SIGNAL go'; +connection dml; +SELECT * FROM child; +a +3 +SET DEBUG_SYNC='foreign_constraint_check_for_update SIGNAL fk WAIT_FOR go'; +DELETE FROM parent; +connection default; +SET DEBUG_SYNC='now WAIT_FOR fk'; +TRUNCATE TABLE child; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SET DEBUG_SYNC='now SIGNAL go'; +connection dml; +ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`a`) REFERENCES `parent` (`a`) ON UPDATE CASCADE) +SELECT * FROM child; +a +3 +INSERT INTO parent SET a=5; +SET DEBUG_SYNC='foreign_constraint_check_for_ins SIGNAL fk WAIT_FOR go'; +INSERT INTO child SET a=5; +connection default; +SET DEBUG_SYNC='now WAIT_FOR fk'; +SET foreign_key_checks=0; +TRUNCATE TABLE parent; +SET DEBUG_SYNC='now SIGNAL go'; +connection dml; +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`child`, CONSTRAINT `child_ibfk_1` FOREIGN KEY (`a`) REFERENCES `parent` (`a`) ON UPDATE CASCADE) +SELECT * FROM parent; +a +SELECT * FROM child; +a +3 +disconnect dml; +connection default; +SET DEBUG_SYNC = RESET; +DROP TABLE child, parent; diff --git a/mysql-test/suite/innodb/r/truncate_inject.result b/mysql-test/suite/innodb/r/truncate_inject.result deleted file mode 100644 index 5ec532a0f83..00000000000 --- a/mysql-test/suite/innodb/r/truncate_inject.result +++ /dev/null @@ -1,114 +0,0 @@ -SET @save_dbug = @@SESSION.debug_dbug; -call mtr.add_suppression("InnoDB: Flagged corruption of .* in table `test`\\.`t` in TRUNCATE TABLE"); -# 1. Error in assigning undo logs for truncate action -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), INDEX ck(c)) -ENGINE = InnoDB; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -check table t; -Table Op Msg_type Msg_text -test.t check status OK -SET debug_dbug = '+d,ib_err_trunc_assigning_undo_log'; -truncate table t; -ERROR HY000: Got error 168 "Unknown (generic) error from engine" from storage engine InnoDB -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -# 2. Error while preparing for truncate -SET debug_dbug = '+d,ib_err_trunc_preparing_for_truncate'; -truncate table t; -ERROR HY000: Got error 168 "Unknown (generic) error from engine" from storage engine InnoDB -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -# 3. Error while dropping/creating indexes -SET debug_dbug = '+d,ib_err_trunc_drop_index'; -truncate table t; -ERROR HY000: Got error 168 "Unknown (generic) error from engine" from storage engine InnoDB -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check Warning InnoDB: Index PRIMARY is marked as corrupted -test.t check error Corrupt -select * from t; -Got one of the listed errors -drop table t; -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), INDEX ck(c)) -ENGINE = InnoDB; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -check table t; -Table Op Msg_type Msg_text -test.t check status OK -SET debug_dbug = '+d,ib_err_trunc_create_index'; -truncate table t; -ERROR HY000: Got error 168 "Unknown (generic) error from engine" from storage engine InnoDB -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check Warning InnoDB: Index PRIMARY is marked as corrupted -test.t check error Corrupt -select * from t; -Got one of the listed errors -drop table t; -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), INDEX ck(c)) -ENGINE = InnoDB; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -check table t; -Table Op Msg_type Msg_text -test.t check status OK -SET debug_dbug = '+d,ib_err_trunc_temp_recreate_index'; -truncate table t; -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -drop table t; -# 4. Error while completing truncate of table involving FTS -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), -FULLTEXT INDEX(c)) ENGINE = InnoDB; -insert into t values (1, 1.1, 'mysql is now oracle company'), -(2, 2.2, 'innodb is part of mysql'), -(3, 3.3, 'innodb is default storage engine of mysql'); -check table t; -Table Op Msg_type Msg_text -test.t check status OK -SET debug_dbug = '+d,ib_err_trunc_temp_recreate_index'; -truncate table t; -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -drop table t; -# 5. Error while updating sys-tables -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), -FULLTEXT INDEX(c)) ENGINE = InnoDB; -insert into t values (1, 1.1, 'mysql is now oracle company'), -(2, 2.2, 'innodb is part of mysql'), -(3, 3.3, 'innodb is default storage engine of mysql'); -check table t; -Table Op Msg_type Msg_text -test.t check status OK -SET debug_dbug = '+d,ib_err_trunc_temp_recreate_index'; -truncate table t; -SET debug_dbug = @save_dbug; -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t order by i; -i f c -drop table t; diff --git a/mysql-test/suite/innodb/r/truncate_missing.result b/mysql-test/suite/innodb/r/truncate_missing.result new file mode 100644 index 00000000000..263880eccd2 --- /dev/null +++ b/mysql-test/suite/innodb/r/truncate_missing.result @@ -0,0 +1,17 @@ +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: Table test/t .* does not exist"); +CREATE TABLE t (a SERIAL) ENGINE=InnoDB; +INSERT INTO t() VALUES(); +SHOW CREATE TABLE t; +Table Create Table +t CREATE TABLE `t` ( + `a` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + UNIQUE KEY `a` (`a`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 +SELECT * FROM t; +ERROR 42S02: Table 'test.t' doesn't exist in engine +TRUNCATE TABLE t; +ERROR 42S02: Table 'test.t' doesn't exist in engine +DROP TABLE t; diff --git a/mysql-test/suite/innodb/r/truncate_purge_debug.result b/mysql-test/suite/innodb/r/truncate_purge_debug.result deleted file mode 100644 index 164987083d5..00000000000 --- a/mysql-test/suite/innodb/r/truncate_purge_debug.result +++ /dev/null @@ -1,29 +0,0 @@ -# -# Bug #23070734 CONCURRENT TRUNCATE TABLES CAUSE STALLS -# -create table t1 (f1 int ,f2 int,key(f2)) engine=innodb; -begin; -insert into t1 values (10,45),(20,78),(30,88),(40,23),(50,78),(60,11),(70,56),(80,90); -delete from t1; -connect con2,localhost,root,,; -START TRANSACTION WITH CONSISTENT SNAPSHOT; -connection default; -SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; -SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; -commit; -connect con1,localhost,root,,; -SET DEBUG_SYNC= 'buffer_pool_scan SIGNAL started WAIT_FOR finish_scan'; -truncate table t1; -connection con2; -SET DEBUG_SYNC= 'now WAIT_FOR started'; -COMMIT; -disconnect con2; -connection default; -InnoDB 0 transactions not purged -SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; -SET DEBUG_SYNC = 'now SIGNAL finish_scan'; -connection con1; -disconnect con1; -connection default; -SET DEBUG_SYNC = 'RESET'; -drop table t1; diff --git a/mysql-test/suite/innodb/r/truncate_restart.result b/mysql-test/suite/innodb/r/truncate_restart.result deleted file mode 100644 index b6d14124371..00000000000 --- a/mysql-test/suite/innodb/r/truncate_restart.result +++ /dev/null @@ -1,12 +0,0 @@ -SET GLOBAL innodb_stats_persistent= ON; -CREATE TABLE t1 (t TEXT) ENGINE=InnoDB STATS_PERSISTENT=1; -connect con1,localhost,root,,test; -SET DEBUG_SYNC='ib_trunc_table_trunc_completing SIGNAL committed WAIT_FOR ever'; -TRUNCATE TABLE t1; -connection default; -SET DEBUG_SYNC='now WAIT_FOR committed'; -disconnect con1; -SELECT COUNT(*) FROM t1; -COUNT(*) -0 -DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/truncate.test b/mysql-test/suite/innodb/t/truncate.test new file mode 100644 index 00000000000..cf71ca83c4c --- /dev/null +++ b/mysql-test/suite/innodb/t/truncate.test @@ -0,0 +1,17 @@ +--source include/have_innodb.inc + +CREATE TABLE t (a SERIAL) ENGINE=InnoDB; + +connect (dml,localhost,root); +# At the end of this statement, close_thread_tables() +# should add the open table handle to the table definition cache (tdc). +select * from t; + +connection default; +# This should purge the handle from the tdc; +# otherwise ha_innobase::truncate() would hang, +# waiting for the reference count to drop to 0. +TRUNCATE TABLE t; +disconnect dml; + +DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/truncate_debug.test b/mysql-test/suite/innodb/t/truncate_debug.test deleted file mode 100644 index 5fee9174d98..00000000000 --- a/mysql-test/suite/innodb/t/truncate_debug.test +++ /dev/null @@ -1,127 +0,0 @@ ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/have_debug_sync.inc - ---source include/count_sessions.inc - ---echo # ---echo # Bug #23070734 CONCURRENT TRUNCATE TABLES CAUSE STALLS ---echo # - -SET @ahi= @@global.innodb_adaptive_hash_index; -# Ensure that there is no adaptive hash index on any system tables, -# or any other tables than the ones that we are creating below. -SET GLOBAL innodb_adaptive_hash_index=OFF; -SET GLOBAL innodb_adaptive_hash_index=ON; - ---echo Test_1 :- Check if DDL operations are possible on ---echo table being truncated. Also check if ---echo DDL operations on other tables succeed. - -create table t1 (f1 int,f2 int,key(f2),f3 int) engine=innodb; -create index idx1 on t1(f3); -create table t2 (f1 int,f2 int,key(f2),f3 int) engine=innodb; -create table t3 (f1 int,f2 int,key(f2)) engine=innodb; - -insert into t1 values (10,20,30),(30,40,50),(50,60,70); -insert into t1 select * from t1; -insert into t1 select * from t1; -insert into t1 select * from t1; -insert into t2 values (10,20,30),(30,40,50),(50,60,70); - -insert into t2 select * from t2; -insert into t2 select * from t2; -insert into t2 select * from t2; - -insert into t3 values (10,20),(30,40),(50,50); -insert into t3 select * from t3; -insert into t3 select * from t3; - -SET session lock_wait_timeout = 1; - -connect (con1,localhost,root,,); -SET DEBUG_SYNC= 'buffer_pool_scan SIGNAL started WAIT_FOR finish_scan'; -send truncate table t1; - -connection default; -SET DEBUG_SYNC= 'now WAIT_FOR started'; - ---echo Check Analyze table. Gives lock time out error. -analyze table t1; - ---echo Check if we can turn off auto recalculation. ---error ER_LOCK_WAIT_TIMEOUT -alter table t1 STATS_AUTO_RECALC=0; - ---echo Check if we can turn off persistent stats on the table ---error ER_LOCK_WAIT_TIMEOUT -alter table t1 STATS_PERSISTENT=0; - ---echo Check if DML is possible on table being truncated ---error ER_LOCK_WAIT_TIMEOUT -insert into t1 values (10,89,99); - ---echo Check if DDL is possible on table being truncated ---error ER_LOCK_WAIT_TIMEOUT -alter table t1 add column f4 int; - ---echo check if table can be created with the same name ---error ER_TABLE_EXISTS_ERROR,ER_LOCK_WAIT_TIMEOUT -create table t1 (bd int) engine=innodb; - ---echo check if index can be created on table being truncated ---error ER_LOCK_WAIT_TIMEOUT -create index idx1 on t1(f1); - ---echo Check if DROP of table is possible during truncate ---error ER_LOCK_WAIT_TIMEOUT -drop table t1; - ---echo Check if select is possible during truncate ---error ER_LOCK_WAIT_TIMEOUT -select * from t1; - ---error ER_BAD_FIELD_ERROR -select * from t2 where t2.f1=t1.f1; - ---echo Check concurrent truncate operation on table; ---error ER_LOCK_WAIT_TIMEOUT -truncate table t1; - ---echo Check concurrent selects and inserts on the other table -insert into t3 values (10,20),(30,40),(50,50); -select * from t3 where f1=40; - ---echo Concurrent truncate on other tables -truncate table t2; - ---echo Concurrent alters on the other tables -alter table t2 add column f4 int; - ---echo check if index can be created on the other table -create index idx1 on t2(f3); - ---echo Check if we can turn off persistent stats off entire instance -SET GLOBAL innodb_stats_persistent=off; - -connect (con2,localhost,root,,); -send set global innodb_adaptive_hash_index=off; - -connection default; -SET DEBUG_SYNC= 'now SIGNAL finish_scan'; - -connection con1; -reap; -disconnect con1; - -connection con2; -reap; -disconnect con2; - -connection default; -SET DEBUG_SYNC= 'RESET'; - -SET GLOBAL innodb_adaptive_hash_index=@ahi; - -drop table t1,t2,t3; ---source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/t/truncate_foreign.test b/mysql-test/suite/innodb/t/truncate_foreign.test new file mode 100644 index 00000000000..2c00c0641e9 --- /dev/null +++ b/mysql-test/suite/innodb/t/truncate_foreign.test @@ -0,0 +1,68 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +CREATE TABLE parent (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO parent SET a=1; + +CREATE TABLE child (a INT PRIMARY KEY, FOREIGN KEY (a) REFERENCES parent(a) +ON UPDATE CASCADE) +ENGINE=InnoDB; +INSERT INTO child SET a=1; + +--error ER_TRUNCATE_ILLEGAL_FK +TRUNCATE TABLE parent; +TRUNCATE TABLE child; + +INSERT INTO child SET a=1; +UPDATE parent SET a=2; +SELECT * FROM child; + +connect (dml,localhost,root); +SET DEBUG_SYNC='foreign_constraint_update_cascade SIGNAL fk WAIT_FOR go'; +send UPDATE parent SET a=3; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR fk'; +SET lock_wait_timeout=1; +--error ER_LOCK_WAIT_TIMEOUT +TRUNCATE TABLE child; +SET DEBUG_SYNC='now SIGNAL go'; + +connection dml; +reap; +SELECT * FROM child; +SET DEBUG_SYNC='foreign_constraint_check_for_update SIGNAL fk WAIT_FOR go'; +send DELETE FROM parent; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR fk'; +--error ER_LOCK_WAIT_TIMEOUT +TRUNCATE TABLE child; +SET DEBUG_SYNC='now SIGNAL go'; + +connection dml; +--error ER_ROW_IS_REFERENCED_2 +reap; +SELECT * FROM child; +INSERT INTO parent SET a=5; +SET DEBUG_SYNC='foreign_constraint_check_for_ins SIGNAL fk WAIT_FOR go'; +send INSERT INTO child SET a=5; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR fk'; +SET foreign_key_checks=0; +TRUNCATE TABLE parent; +SET DEBUG_SYNC='now SIGNAL go'; + +connection dml; +--error ER_NO_REFERENCED_ROW_2 +reap; +SELECT * FROM parent; +SELECT * FROM child; +disconnect dml; + +connection default; +SET DEBUG_SYNC = RESET; + +DROP TABLE child, parent; diff --git a/mysql-test/suite/innodb/t/truncate_inject.test b/mysql-test/suite/innodb/t/truncate_inject.test deleted file mode 100644 index 35e516324bb..00000000000 --- a/mysql-test/suite/innodb/t/truncate_inject.test +++ /dev/null @@ -1,97 +0,0 @@ -# This test is based on innodb_zip.wl6501_error_1 in MySQL 5.7. - ---source include/have_innodb.inc ---source include/innodb_row_format.inc ---source include/have_debug.inc - -SET @save_dbug = @@SESSION.debug_dbug; - -call mtr.add_suppression("InnoDB: Flagged corruption of .* in table `test`\\.`t` in TRUNCATE TABLE"); - ---echo # 1. Error in assigning undo logs for truncate action -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), INDEX ck(c)) -ENGINE = InnoDB; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -check table t; -# -SET debug_dbug = '+d,ib_err_trunc_assigning_undo_log'; ---error ER_GET_ERRNO -truncate table t; -SET debug_dbug = @save_dbug; -check table t; -select * from t; - ---echo # 2. Error while preparing for truncate -SET debug_dbug = '+d,ib_err_trunc_preparing_for_truncate'; ---error ER_GET_ERRNO -truncate table t; -SET debug_dbug = @save_dbug; -check table t; -select * from t; - ---echo # 3. Error while dropping/creating indexes -SET debug_dbug = '+d,ib_err_trunc_drop_index'; ---error ER_GET_ERRNO -truncate table t; -SET debug_dbug = @save_dbug; -check table t; ---error ER_TABLE_CORRUPT,ER_GET_ERRNO -select * from t; -drop table t; - -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), INDEX ck(c)) -ENGINE = InnoDB; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -check table t; - -SET debug_dbug = '+d,ib_err_trunc_create_index'; ---error ER_GET_ERRNO -truncate table t; -SET debug_dbug = @save_dbug; -check table t; ---error ER_TABLE_CORRUPT,ER_GET_ERRNO -select * from t; -drop table t; - -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), INDEX ck(c)) -ENGINE = InnoDB; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -check table t; - -SET debug_dbug = '+d,ib_err_trunc_temp_recreate_index'; -truncate table t; -SET debug_dbug = @save_dbug; - -check table t; -select * from t; -drop table t; - ---echo # 4. Error while completing truncate of table involving FTS -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), -FULLTEXT INDEX(c)) ENGINE = InnoDB; -insert into t values (1, 1.1, 'mysql is now oracle company'), - (2, 2.2, 'innodb is part of mysql'), - (3, 3.3, 'innodb is default storage engine of mysql'); -check table t; -SET debug_dbug = '+d,ib_err_trunc_temp_recreate_index'; -truncate table t; -SET debug_dbug = @save_dbug; - -check table t; -select * from t; -drop table t; - ---echo # 5. Error while updating sys-tables -CREATE TABLE t (i int PRIMARY KEY, f float UNIQUE, c char(100), -FULLTEXT INDEX(c)) ENGINE = InnoDB; -insert into t values (1, 1.1, 'mysql is now oracle company'), - (2, 2.2, 'innodb is part of mysql'), - (3, 3.3, 'innodb is default storage engine of mysql'); -check table t; -SET debug_dbug = '+d,ib_err_trunc_temp_recreate_index'; -truncate table t; -SET debug_dbug = @save_dbug; - -check table t; -select * from t order by i; -drop table t; diff --git a/mysql-test/suite/innodb/t/truncate_missing.test b/mysql-test/suite/innodb/t/truncate_missing.test new file mode 100644 index 00000000000..832b94e3a19 --- /dev/null +++ b/mysql-test/suite/innodb/t/truncate_missing.test @@ -0,0 +1,22 @@ +--source include/have_innodb.inc +--source include/not_embedded.inc + +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: Table test/t .* does not exist"); + +CREATE TABLE t (a SERIAL) ENGINE=InnoDB; +INSERT INTO t() VALUES(); +SHOW CREATE TABLE t; +let $datadir=`select @@datadir`; + +--source include/shutdown_mysqld.inc +--remove_file $datadir/test/t.ibd +--source include/start_mysqld.inc + +--error ER_NO_SUCH_TABLE_IN_ENGINE +SELECT * FROM t; +--error ER_NO_SUCH_TABLE_IN_ENGINE +TRUNCATE TABLE t; +DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/truncate_purge_debug.opt b/mysql-test/suite/innodb/t/truncate_purge_debug.opt deleted file mode 100644 index 8bed7e46166..00000000000 --- a/mysql-test/suite/innodb/t/truncate_purge_debug.opt +++ /dev/null @@ -1,3 +0,0 @@ ---innodb-purge-threads=1 ---innodb-purge-batch-size=1 ---innodb-stats-persistent=OFF diff --git a/mysql-test/suite/innodb/t/truncate_purge_debug.test b/mysql-test/suite/innodb/t/truncate_purge_debug.test deleted file mode 100644 index e8f5768f557..00000000000 --- a/mysql-test/suite/innodb/t/truncate_purge_debug.test +++ /dev/null @@ -1,49 +0,0 @@ ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/have_debug_sync.inc ---source include/count_sessions.inc - ---echo # ---echo # Bug #23070734 CONCURRENT TRUNCATE TABLES CAUSE STALLS ---echo # - -create table t1 (f1 int ,f2 int,key(f2)) engine=innodb; -begin; -insert into t1 values (10,45),(20,78),(30,88),(40,23),(50,78),(60,11),(70,56),(80,90); -delete from t1; - -connect (con2,localhost,root,,); -# Stop the purge thread -START TRANSACTION WITH CONSISTENT SNAPSHOT; - -connection default; -# Ensure that the history list length will actually be decremented by purge. -SET @saved_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; -SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; -commit; - -connect (con1,localhost,root,,); -SET DEBUG_SYNC= 'buffer_pool_scan SIGNAL started WAIT_FOR finish_scan'; -send truncate table t1; - -connection con2; -SET DEBUG_SYNC= 'now WAIT_FOR started'; -# Allow purge to proceed, by discarding our read view. -COMMIT; -disconnect con2; - -connection default; ---source include/wait_all_purged.inc - -SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; - -SET DEBUG_SYNC = 'now SIGNAL finish_scan'; - -connection con1; -reap; -disconnect con1; - -connection default; -SET DEBUG_SYNC = 'RESET'; -drop table t1; ---source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/t/truncate_restart.test b/mysql-test/suite/innodb/t/truncate_restart.test deleted file mode 100644 index 60a3d83cd81..00000000000 --- a/mysql-test/suite/innodb/t/truncate_restart.test +++ /dev/null @@ -1,16 +0,0 @@ ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/have_debug_sync.inc - -SET GLOBAL innodb_stats_persistent= ON; -CREATE TABLE t1 (t TEXT) ENGINE=InnoDB STATS_PERSISTENT=1; ---connect (con1,localhost,root,,test) -SET DEBUG_SYNC='ib_trunc_table_trunc_completing SIGNAL committed WAIT_FOR ever'; ---send -TRUNCATE TABLE t1; ---connection default -SET DEBUG_SYNC='now WAIT_FOR committed'; ---source include/restart_mysqld.inc ---disconnect con1 -SELECT COUNT(*) FROM t1; -DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/r/truncate.result b/mysql-test/suite/innodb_fts/r/truncate.result deleted file mode 100644 index 0e21717a4d3..00000000000 --- a/mysql-test/suite/innodb_fts/r/truncate.result +++ /dev/null @@ -1,31 +0,0 @@ -# -# Bug#25053705 - INVALID I/O ON TABLE AFTER TRUNCATE -# -CREATE TABLE t1 (a INT, d INT, b VARCHAR(198), c CHAR(158), FULLTEXT fts1(c,b), -FULLTEXT fts2(c)); -TRUNCATE TABLE t1; -INSERT INTO t1 (a,d,b,c) VALUES ( -'79795','6',repeat('uololoaroolccaaruolraloouuoocorrcorurlu','1'), -repeat('orouculcaocuocloooolooloooaorlroclouulrrucclulalouaulrluorooaclllluuorc -cuullucocraloracurooulrooauuar','1')); -CREATE TABLE t2 (a INT, d INT, b VARCHAR(198), c CHAR(158), FULLTEXT fts1(c,b)); -INSERT INTO t2 VALUES (1, 1, repeat('uololoaroolccaaruolraloouuoocorrcorurlu','1'), -repeat('orouculcaocuocloooolooloooaorlroclouulrrucclulalouaulrluorooaclllluuorccuullucocraloracurooulrooauuar','1')); -create procedure insert_t2(IN total int) -begin -declare i int default 1; -while (i <= total) DO -insert into t2 select * from t2; -set i = i + 1; -end while; -end| -CALL insert_t2(15); -SET @save_dbug = @@SESSION.DEBUG_DBUG; -SET DEBUG_DBUG = '+d,innodb_invalid_read_after_truncate'; -INSERT INTO t1 (a,d,b,c) VALUES ( -'7795','6',repeat('uololoaroolccaaruolraloouuoocorrcorurlu','1'), -repeat('orouculcaocuocloooolooloooaorlroclouulrrucclulalouaulrluorooaclllluuorc -cuullucocraloracurooulrooauuar','1')); -SET DEBUG_DBUG = @save_dbug; -DROP PROCEDURE insert_t2; -DROP TABLE t1,t2; diff --git a/mysql-test/suite/innodb_fts/t/truncate.opt b/mysql-test/suite/innodb_fts/t/truncate.opt deleted file mode 100644 index d143088d352..00000000000 --- a/mysql-test/suite/innodb_fts/t/truncate.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb-random-read-ahead=1 diff --git a/mysql-test/suite/innodb_fts/t/truncate.test b/mysql-test/suite/innodb_fts/t/truncate.test deleted file mode 100644 index 46ba732b019..00000000000 --- a/mysql-test/suite/innodb_fts/t/truncate.test +++ /dev/null @@ -1,50 +0,0 @@ ---source include/have_innodb.inc ---source include/have_debug.inc - ---echo # ---echo # Bug#25053705 - INVALID I/O ON TABLE AFTER TRUNCATE ---echo # - -CREATE TABLE t1 (a INT, d INT, b VARCHAR(198), c CHAR(158), FULLTEXT fts1(c,b), -FULLTEXT fts2(c)); - -TRUNCATE TABLE t1; - -INSERT INTO t1 (a,d,b,c) VALUES ( -'79795','6',repeat('uololoaroolccaaruolraloouuoocorrcorurlu','1'), -repeat('orouculcaocuocloooolooloooaorlroclouulrrucclulalouaulrluorooaclllluuorc -cuullucocraloracurooulrooauuar','1')); - -# The following CREATE TABLE and INSERTs are used to remove the pages related to table t1 -# from the buffer pool. -CREATE TABLE t2 (a INT, d INT, b VARCHAR(198), c CHAR(158), FULLTEXT fts1(c,b)); - -INSERT INTO t2 VALUES (1, 1, repeat('uololoaroolccaaruolraloouuoocorrcorurlu','1'), -repeat('orouculcaocuocloooolooloooaorlroclouulrrucclulalouaulrluorooaclllluuorccuullucocraloracurooulrooauuar','1')); - -delimiter |; -create procedure insert_t2(IN total int) -begin - declare i int default 1; - while (i <= total) DO - insert into t2 select * from t2; - set i = i + 1; - end while; -end| -delimiter ;| - -CALL insert_t2(15); - -SET @save_dbug = @@SESSION.DEBUG_DBUG; -SET DEBUG_DBUG = '+d,innodb_invalid_read_after_truncate'; - -INSERT INTO t1 (a,d,b,c) VALUES ( -'7795','6',repeat('uololoaroolccaaruolraloouuoocorrcorurlu','1'), -repeat('orouculcaocuocloooolooloooaorlroclouulrrucclulalouaulrluorooaclllluuorc -cuullucocraloracurooulrooauuar','1')); - -SET DEBUG_DBUG = @save_dbug; - -DROP PROCEDURE insert_t2; - -DROP TABLE t1,t2; diff --git a/mysql-test/suite/innodb_undo/include/truncate_recover.inc b/mysql-test/suite/innodb_undo/include/truncate_recover.inc deleted file mode 100644 index fe068afa6e3..00000000000 --- a/mysql-test/suite/innodb_undo/include/truncate_recover.inc +++ /dev/null @@ -1,8 +0,0 @@ -begin; -update t1 set c = 'MariaDB'; -update t1 set c = 'InnoDB'; -eval set global debug_dbug = '+d,$SEARCH_PATTERN'; -commit; ---source include/shutdown_mysqld.inc ---source include/search_pattern_in_file.inc ---source include/start_mysqld.inc diff --git a/mysql-test/suite/innodb_undo/r/truncate.result b/mysql-test/suite/innodb_undo/r/truncate.result index 4f62d85e08a..2194eed3e7b 100644 --- a/mysql-test/suite/innodb_undo/r/truncate.result +++ b/mysql-test/suite/innodb_undo/r/truncate.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("InnoDB: The transaction log size is too large"); SET GLOBAL innodb_fast_shutdown=0; create table t1(keyc int primary key, c1 char(100)) engine = innodb; begin; diff --git a/mysql-test/suite/innodb_undo/r/truncate_multi_client.result b/mysql-test/suite/innodb_undo/r/truncate_multi_client.result index c1ce2845996..0333a70d771 100644 --- a/mysql-test/suite/innodb_undo/r/truncate_multi_client.result +++ b/mysql-test/suite/innodb_undo/r/truncate_multi_client.result @@ -1,3 +1,4 @@ +call mtr.add_suppression("InnoDB: The transaction log size is too large"); SET GLOBAL innodb_fast_shutdown=0; create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; diff --git a/mysql-test/suite/innodb_undo/r/truncate_recover.result b/mysql-test/suite/innodb_undo/r/truncate_recover.result index f89bc0a9e47..ae33474e00d 100644 --- a/mysql-test/suite/innodb_undo/r/truncate_recover.result +++ b/mysql-test/suite/innodb_undo/r/truncate_recover.result @@ -1,15 +1,15 @@ +SET GLOBAL innodb_undo_logs = 4; +SET GLOBAL innodb_undo_log_truncate = 1; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; create table t1(keyc int primary key, c char(100)) engine = innodb; begin; commit; begin; update t1 set c = 'MariaDB'; update t1 set c = 'InnoDB'; -set global debug_dbug = '+d,ib_undo_trunc_before_truncate'; +set global debug_dbug = '+d,ib_undo_trunc'; commit; -FOUND 1 /ib_undo_trunc_before_truncate/ in mysqld.1.err -begin; -update t1 set c = 'MariaDB'; -update t1 set c = 'InnoDB'; -set global debug_dbug = '+d,ib_undo_trunc_before_ddl_log_end'; -commit; -FOUND 1 /ib_undo_trunc_before_ddl_log_end/ in mysqld.1.err +call mtr.add_suppression("InnoDB: The transaction log size is too large"); +SET GLOBAL innodb_fast_shutdown=0; +FOUND 1 /ib_undo_trunc/ in mysqld.1.err +drop table t1; diff --git a/mysql-test/suite/innodb_undo/t/truncate.test b/mysql-test/suite/innodb_undo/t/truncate.test index 2c612478929..cc18434ae13 100644 --- a/mysql-test/suite/innodb_undo/t/truncate.test +++ b/mysql-test/suite/innodb_undo/t/truncate.test @@ -9,6 +9,7 @@ # The test is restarting the server to force undo truncation. --source include/not_embedded.inc +call mtr.add_suppression("InnoDB: The transaction log size is too large"); SET GLOBAL innodb_fast_shutdown=0; --let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_undo_logs=4 --source include/restart_mysqld.inc diff --git a/mysql-test/suite/innodb_undo/t/truncate_multi_client.test b/mysql-test/suite/innodb_undo/t/truncate_multi_client.test index ac4ead00b51..6a3d702d0d5 100644 --- a/mysql-test/suite/innodb_undo/t/truncate_multi_client.test +++ b/mysql-test/suite/innodb_undo/t/truncate_multi_client.test @@ -9,6 +9,7 @@ --source include/have_innodb_max_16k.inc --source include/have_undo_tablespaces.inc +call mtr.add_suppression("InnoDB: The transaction log size is too large"); SET GLOBAL innodb_fast_shutdown=0; --let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_undo_logs=4 --source include/restart_mysqld.inc diff --git a/mysql-test/suite/innodb_undo/t/truncate_recover.test b/mysql-test/suite/innodb_undo/t/truncate_recover.test index 8087d191f1e..fb901bc4259 100644 --- a/mysql-test/suite/innodb_undo/t/truncate_recover.test +++ b/mysql-test/suite/innodb_undo/t/truncate_recover.test @@ -2,10 +2,10 @@ # WL#6965: Truncate UNDO logs. # +# With larger innodb_page_size, the undo log tablespaces do not grow enough. +--source include/innodb_page_size_small.inc --source include/have_innodb.inc --source include/have_debug.inc -# With larger innodb_page_size, the undo log tablespaces do not grow enough. ---source include/have_innodb_max_16k.inc --source include/have_undo_tablespaces.inc # Valgrind would complain about memory leaks when we crash on purpose. @@ -15,15 +15,9 @@ # Avoid CrashReporter popup on Mac --source include/not_crashrep.inc ---disable_query_log -# FIXME: The doublewrite buffer should not issue these warnings. -# FIXME: Maybe buf_dblwr_process() should empty the buffer at the end? -call mtr.add_suppression("InnoDB: A copy of page.*in the doublewrite buffer slot.*is not within space bounds"); -FLUSH TABLES; ---enable_query_log - ---let $restart_parameters=--innodb-undo-logs=4 --innodb-undo-tablespaces=2 --innodb-undo-log-truncate=1 --innodb-max-undo-log-size=10485760 --innodb-purge-rseg-truncate-frequency=1 --innodb-fast-shutdown=0 ---source include/restart_mysqld.inc +SET GLOBAL innodb_undo_logs = 4; +SET GLOBAL innodb_undo_log_truncate = 1; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err; @@ -38,13 +32,19 @@ while ($i) { --enable_query_log commit; -let SEARCH_PATTERN = ib_undo_trunc_before_truncate; ---source include/truncate_recover.inc +let SEARCH_PATTERN = ib_undo_trunc; +begin; +update t1 set c = 'MariaDB'; +update t1 set c = 'InnoDB'; +eval set global debug_dbug = '+d,$SEARCH_PATTERN'; +commit; +# FIXME: remove this work-around, and generate less log! +call mtr.add_suppression("InnoDB: The transaction log size is too large"); +SET GLOBAL innodb_fast_shutdown=0; +--source include/shutdown_mysqld.inc +--source include/search_pattern_in_file.inc +# FIXME: remove this work-around, and generate less log! +--let $restart_parameters= --innodb-buffer-pool-size=16m +--source include/start_mysqld.inc -let SEARCH_PATTERN = ib_undo_trunc_before_ddl_log_end; ---source include/truncate_recover.inc - -let SEARCH_PATTERN = ib_undo_trunc_trunc_done; -let $restart_parameters= ---source include/truncate_recover.inc drop table t1; diff --git a/mysql-test/suite/innodb_zip/include/innodb_wl6501_scale.inc b/mysql-test/suite/innodb_zip/include/innodb_wl6501_scale.inc deleted file mode 100644 index bef28a9c484..00000000000 --- a/mysql-test/suite/innodb_zip/include/innodb_wl6501_scale.inc +++ /dev/null @@ -1,112 +0,0 @@ -# -# load tables with some significant amount of data and then truncate it. -# - -#----------------------------------------------------------------------------- -# -# create test-bed -# -let $per_table = `select @@innodb_file_per_table`; -let $format = `select @@innodb_file_format`; - -let $WL6501_TMP_DIR = `select @@tmpdir`; -let $WL6501_DATA_DIR = `select @@datadir`; -set innodb_strict_mode=OFF; - -#----------------------------------------------------------------------------- -# -# create procedure to load data -# -delimiter |; -create procedure populate() -begin - declare i int default 1; - while (i <= 5000) do - insert into t1 values (i, 'a', 'b'); - insert into t2 values (i, 'a', 'b'); - insert into t3 values (i, 'a', 'b'); - set i = i + 1; - end while; -end| -create procedure populate_small() -begin - declare i int default 10001; - while (i <= 12000) do - insert into t1 values (i, 'c', 'd'); - insert into t2 values (i, 'a', 'b'); - insert into t3 values (i, 'a', 'b'); - set i = i + 1; - end while; -end| -delimiter ;| - -#----------------------------------------------------------------------------- -# -# create and load the tables. -# -eval set global innodb_file_per_table = $wl6501_file_per_table; ---replace_regex /[0-9]+/NUMBER/ -eval create table t1 - (i int, c1 char(100), c2 char(100), - index c1_idx(c1)) - engine=innodb row_format=$wl6501_row_fmt - key_block_size=$wl6501_kbs; -eval create table t2 - (i int, c1 char(100), c2 char(100), - index c1_idx(c1)) - engine=innodb row_format=$wl6501_row_fmt - key_block_size=$wl6501_kbs; -eval create temporary table t3 - (i int, c1 char(100), c2 char(100), - index c1_idx(c1)) - engine=innodb row_format=$wl6501_row_fmt - key_block_size=$wl6501_kbs; -# -select count(*) from t1; -select count(*) from t2; -select count(*) from t3; -begin; -call populate(); -commit; -select count(*) from t1; -select count(*) from t2; -select count(*) from t3; -# -truncate table t1; -select count(*) from t1; -select count(*) from t2; -select count(*) from t3; -# -call populate_small(); -select count(*) from t1; -select count(*) from t2; -select count(*) from t3; -# -truncate table t2; -truncate table t3; -select count(*) from t1; -select count(*) from t2; -select count(*) from t3; -# -call populate_small(); -select count(*) from t1; -select count(*) from t2; -select count(*) from t3; -# -drop table t1; -drop table t2; -drop table t3; - -#----------------------------------------------------------------------------- -# -# drop the procedure -# -drop procedure populate; -drop procedure populate_small; - -#----------------------------------------------------------------------------- -# -# remove test-bed -# -eval set global innodb_file_format = $format; -eval set global innodb_file_per_table = $per_table; diff --git a/mysql-test/suite/innodb_zip/r/restart.result b/mysql-test/suite/innodb_zip/r/restart.result index c4e6daf73fe..5102ebe4fe3 100644 --- a/mysql-test/suite/innodb_zip/r/restart.result +++ b/mysql-test/suite/innodb_zip/r/restart.result @@ -418,12 +418,12 @@ ALTER TABLE t7_restart TRUNCATE PARTITION p1; === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === Space_Name Space_Type Page_Size Zip_Size Formats_Permitted Path test/t4_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t4_restart.ibd -test/t5_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t5_restart.ibd test/t6_restart#p#p0 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p0.ibd test/t6_restart#p#p1 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p1.ibd -test/t6_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p2.ibd test/t7_restart#p#p0#sp#s0 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p0#sp#s0.ibd test/t7_restart#p#p0#sp#s1 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p0#sp#s1.ibd +test/t5_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t5_restart.ibd +test/t6_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p2.ibd test/t7_restart#p#p1#sp#s2 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p1#sp#s2.ibd test/t7_restart#p#p1#sp#s3 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p1#sp#s3.ibd INSERT INTO t5_restart VALUES (1000000000, 'MySQL', 'InnoDB', '2011-11-11', 'Read this after reboot'); @@ -521,12 +521,12 @@ innodb_file_per_table ON === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === Space_Name Space_Type Page_Size Zip_Size Formats_Permitted Path test/t4_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t4_restart.ibd -test/t5_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t5_restart.ibd test/t6_restart#p#p0 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p0.ibd test/t6_restart#p#p1 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p1.ibd -test/t6_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p2.ibd test/t7_restart#p#p0#sp#s0 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p0#sp#s0.ibd test/t7_restart#p#p0#sp#s1 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p0#sp#s1.ibd +test/t5_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t5_restart.ibd +test/t6_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t6_restart#p#p2.ibd test/t7_restart#p#p1#sp#s2 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p1#sp#s2.ibd test/t7_restart#p#p1#sp#s3 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t7_restart#p#p1#sp#s3.ibd SELECT count(*) FROM t5_restart; @@ -621,12 +621,12 @@ RENAME TABLE t7_restart TO t77_restart; === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === Space_Name Space_Type Page_Size Zip_Size Formats_Permitted Path test/t4_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t4_restart.ibd -test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t55_restart.ibd test/t66_restart#p#p0 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p0.ibd test/t66_restart#p#p1 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p1.ibd -test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p2.ibd test/t77_restart#p#p0#sp#s0 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p0#sp#s0.ibd test/t77_restart#p#p0#sp#s1 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p0#sp#s1.ibd +test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t55_restart.ibd +test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p2.ibd test/t77_restart#p#p1#sp#s2 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p1#sp#s2.ibd test/t77_restart#p#p1#sp#s3 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p1#sp#s3.ibd INSERT INTO t55_restart (SELECT 0, c2, c3, c4, c5 FROM t55_restart); @@ -717,12 +717,12 @@ innodb_file_per_table ON === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === Space_Name Space_Type Page_Size Zip_Size Formats_Permitted Path test/t4_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t4_restart.ibd -test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t55_restart.ibd test/t66_restart#p#p0 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p0.ibd test/t66_restart#p#p1 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p1.ibd -test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p2.ibd test/t77_restart#p#p0#sp#s0 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p0#sp#s0.ibd test/t77_restart#p#p0#sp#s1 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p0#sp#s1.ibd +test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t55_restart.ibd +test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/alt_dir/test/t66_restart#p#p2.ibd test/t77_restart#p#p1#sp#s2 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p1#sp#s2.ibd test/t77_restart#p#p1#sp#s3 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/alt_dir/test/t77_restart#p#p1#sp#s3.ibd INSERT INTO t55_restart (SELECT 0, c2, c3, c4, c5 FROM t55_restart); @@ -848,12 +848,12 @@ t77_restart#p#p1#sp#s3.ibd === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === Space_Name Space_Type Page_Size Zip_Size Formats_Permitted Path test/t4_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t4_restart.ibd -test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t55_restart.ibd test/t66_restart#p#p0 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/new_dir/test/t66_restart#p#p0.ibd test/t66_restart#p#p1 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/new_dir/test/t66_restart#p#p1.ibd -test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/new_dir/test/t66_restart#p#p2.ibd test/t77_restart#p#p0#sp#s0 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t77_restart#p#p0#sp#s0.ibd test/t77_restart#p#p0#sp#s1 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t77_restart#p#p0#sp#s1.ibd +test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t55_restart.ibd +test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQL_TMP_DIR/new_dir/test/t66_restart#p#p2.ibd test/t77_restart#p#p1#sp#s2 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t77_restart#p#p1#sp#s2.ibd test/t77_restart#p#p1#sp#s3 Single DEFAULT DEFAULT Dynamic MYSQL_TMP_DIR/new_dir/test/t77_restart#p#p1#sp#s3.ibd INSERT INTO t4_restart (SELECT 0, c2, c3, c4, c5 FROM t4_restart); @@ -983,12 +983,12 @@ t77_restart.par === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles === Space_Name Space_Type Page_Size Zip_Size Formats_Permitted Path test/t4_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t4_restart.ibd -test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t55_restart.ibd test/t66_restart#p#p0 Single DEFAULT DEFAULT Compressed MYSQLD_DATADIR/test/t66_restart#p#p0.ibd test/t66_restart#p#p1 Single DEFAULT DEFAULT Compressed MYSQLD_DATADIR/test/t66_restart#p#p1.ibd -test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQLD_DATADIR/test/t66_restart#p#p2.ibd test/t77_restart#p#p0#sp#s0 Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t77_restart#p#p0#sp#s0.ibd test/t77_restart#p#p0#sp#s1 Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t77_restart#p#p0#sp#s1.ibd +test/t55_restart Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t55_restart.ibd +test/t66_restart#p#p2 Single DEFAULT DEFAULT Compressed MYSQLD_DATADIR/test/t66_restart#p#p2.ibd test/t77_restart#p#p1#sp#s2 Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t77_restart#p#p1#sp#s2.ibd test/t77_restart#p#p1#sp#s3 Single DEFAULT DEFAULT Dynamic MYSQLD_DATADIR/test/t77_restart#p#p1#sp#s3.ibd INSERT INTO t4_restart (SELECT 0, c2, c3, c4, c5 FROM t4_restart); diff --git a/mysql-test/suite/innodb_zip/r/wl6501_1.result b/mysql-test/suite/innodb_zip/r/wl6501_1.result deleted file mode 100644 index bf901804be5..00000000000 --- a/mysql-test/suite/innodb_zip/r/wl6501_1.result +++ /dev/null @@ -1,1202 +0,0 @@ -set global innodb_file_per_table=on; -# Verify that 'TRUNCATE TABLE' statement works fine and the size -# of .ibd file is equal to the initial size after truncation. -drop table if exists t1,t2,t3,t4,t6; -Warnings: -Note 1051 Unknown table 'test.t1' -Note 1051 Unknown table 'test.t2' -Note 1051 Unknown table 'test.t3' -Note 1051 Unknown table 'test.t4' -Note 1051 Unknown table 'test.t6' -create table t1(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=redundant; -create table t2(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compact; -create table t3(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compressed key_block_size=4; -create table t4(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=dynamic; -create temporary table t5(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb; -create table t6 ( a int ) engine = innodb; -insert into t6 values (50),(100),(150); -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -count(*) -3 -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_during_drop_index_temp_table"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_during_drop_index_temp_table point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t5; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_drop_of_sec_index point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t1; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_drop_of_sec_index point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t2; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_drop_of_sec_index point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t3; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_drop_of_sec_index point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t4; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -0 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -drop table t1, t2, t3, t4, t6; -create table t1(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=redundant; -create table t2(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compact; -create table t3(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compressed key_block_size=4; -create table t4(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=dynamic; -create temporary table t5(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb; -create table t6 ( a int ) engine = innodb; -insert into t6 values (50),(100),(150); -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -count(*) -3 -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_drop_reinit_done_create_to_start"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_drop_reinit_done_create_to_start---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t5; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_create_of_sec_index---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t1; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_create_of_sec_index---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t2; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_create_of_sec_index---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t3; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_on_create_of_sec_index---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t4; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -0 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -drop table t1, t2, t3, t4, t6; -create table t1(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=redundant; -create table t2(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compact; -create table t3(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compressed key_block_size=4; -create table t4(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=dynamic; -create temporary table t5(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb; -create table t6 ( a int ) engine = innodb; -insert into t6 values (50),(100),(150); -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -count(*) -3 -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_before_log_removal point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t1; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_before_log_removal point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t2; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_before_log_removal point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t3; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_before_log_removal point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t4; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -0 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -drop table t1, t2, t3, t4, t6; -create table t1(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=redundant; -create table t2(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compact; -create table t3(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compressed key_block_size=4; -create table t4(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=dynamic; -create temporary table t5(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb; -create table t6 ( a int ) engine = innodb; -insert into t6 values (50),(100),(150); -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -count(*) -3 -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t1; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t2; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t3; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t4; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -0 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -drop table t1, t2, t3, t4, t6; -create table t1(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=redundant; -create table t2(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compact; -create table t3(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compressed key_block_size=4; -create table t4(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=dynamic; -create temporary table t5(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb; -create table t6 ( a int ) engine = innodb; -insert into t6 values (50),(100),(150); -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -count(*) -3 -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t1; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t2; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t3; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_truncate_done point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t4; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -0 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -drop table t1, t2, t3, t4, t6; -create table t1(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=redundant; -create table t2(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compact; -create table t3(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=compressed key_block_size=4; -create table t4(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb row_format=dynamic; -create temporary table t5(c1 int not null, -c2 int not null, -c3 char(255) not null, -c4 text(500) not null, -c5 blob(500) not null, -c6 varchar(500) not null, -c7 varchar(500) not null, -c8 datetime, -c9 decimal(5,3), -primary key (c1), -index (c3,c4(50),c5(50)), -index (c2)) -engine=innodb; -create table t6 ( a int ) engine = innodb; -insert into t6 values (50),(100),(150); -select count(*) from t1; -count(*) -3 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -count(*) -3 -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_redo_log_write_complete point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t1; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -3 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_redo_log_write_complete point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t2; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -3 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_redo_log_write_complete point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t3; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -3 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -"---debug ib_trunc_crash_after_redo_log_write_complete point---" -# Write file to make mysql-test-run.pl expect crash and restart -# Run the crashing query -truncate table t4; -ERROR HY000: Lost connection to MySQL server during query -# Restart the MySQL server -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -select count(*) from t4; -count(*) -0 -select count(*) from t5; -ERROR 42S02: Table 'test.t5' doesn't exist -select count(*) from t6; -count(*) -3 -drop table t1, t2, t3, t4, t6; diff --git a/mysql-test/suite/innodb_zip/r/wl6501_crash_3.result b/mysql-test/suite/innodb_zip/r/wl6501_crash_3.result deleted file mode 100644 index 554bb2892f6..00000000000 --- a/mysql-test/suite/innodb_zip/r/wl6501_crash_3.result +++ /dev/null @@ -1,462 +0,0 @@ -call mtr.add_suppression("The file '.*' already exists though the corresponding table did not exist in the InnoDB data dictionary"); -call mtr.add_suppression("Cannot create file '.*'"); -call mtr.add_suppression("InnoDB: Error number 17 means 'File exists'"); -set global innodb_file_per_table = on; -"1. Hit crash point while writing redo log." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine=innodb row_format=compressed -key_block_size=16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_while_writing_redo_log"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"2. Hit crash point on completion of redo log write." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"3. Hit crash point while dropping indexes." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_clust_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_uniq_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"4. Hit crash point on completing drop of all indexes before creation" -" of index is commenced." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_drop_reinit_done_create_to_start"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"5. Hit crash point while creating indexes." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_clust_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_uniq_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"6. Hit crash point after data is updated to system-table and" -" in-memory dict." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_updating_dict_sys_info"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"7. Hit crash point before/after log checkpoint is done." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 16; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -set global innodb_file_per_table = 1; diff --git a/mysql-test/suite/innodb_zip/r/wl6501_crash_4.result b/mysql-test/suite/innodb_zip/r/wl6501_crash_4.result deleted file mode 100644 index d766ecceaac..00000000000 --- a/mysql-test/suite/innodb_zip/r/wl6501_crash_4.result +++ /dev/null @@ -1,519 +0,0 @@ -call mtr.add_suppression("The file '.*' already exists though the corresponding table did not exist in the InnoDB data dictionary"); -call mtr.add_suppression("Cannot create file '.*'"); -call mtr.add_suppression("InnoDB: Error number 17 means 'File exists'"); -set global innodb_file_per_table = on; -"1. Hit crash point while writing redo log." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine=innodb row_format=compressed -key_block_size=4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_while_writing_redo_log"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"2. Hit crash point on completion of redo log write." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"3. Hit crash point while dropping indexes." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_clust_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_uniq_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"4. Hit crash point on completing drop of all indexes before creation" -" of index is commenced." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_drop_reinit_done_create_to_start"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"5. Hit crash point while creating indexes." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_clust_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_uniq_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"6. Hit crash point after data is updated to system-table and" -" in-memory dict." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_updating_dict_sys_info"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"7. Hit crash point before/after log checkpoint is done." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -set global innodb_file_per_table = 1; -call mtr.add_suppression("does not exist in the InnoDB internal"); -set global innodb_file_per_table = on; -"1. Hit crash point on completing drop of all indexes before creation" -" of index is commenced." -set global innodb_file_per_table = 1; -set innodb_strict_mode=off; -create temporary table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_drop_reinit_done_create_to_start"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check Error Table 'test.t' doesn't exist -test.t check status Operation failed -"2. Hit crash point after data is updated to system-table and" -" in-memory dict." -set global innodb_file_per_table = 1; -set innodb_strict_mode=off; -create temporary table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 4; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_updating_dict_sys_info"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check Error Table 'test.t' doesn't exist -test.t check status Operation failed -set global innodb_file_per_table = 1; diff --git a/mysql-test/suite/innodb_zip/r/wl6501_crash_5.result b/mysql-test/suite/innodb_zip/r/wl6501_crash_5.result deleted file mode 100644 index b5fea6382ff..00000000000 --- a/mysql-test/suite/innodb_zip/r/wl6501_crash_5.result +++ /dev/null @@ -1,462 +0,0 @@ -call mtr.add_suppression("The file '.*' already exists though the corresponding table did not exist in the InnoDB data dictionary"); -call mtr.add_suppression("Cannot create file '.*'"); -call mtr.add_suppression("InnoDB: Error number 17 means 'File exists'"); -set global innodb_file_per_table = on; -"1. Hit crash point while writing redo log." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine=innodb row_format=compressed -key_block_size=8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_while_writing_redo_log"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"2. Hit crash point on completion of redo log write." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_after_redo_log_write_complete"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"3. Hit crash point while dropping indexes." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_clust_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_uniq_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_drop_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"4. Hit crash point on completing drop of all indexes before creation" -" of index is commenced." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_drop_reinit_done_create_to_start"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"5. Hit crash point while creating indexes." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_clust_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_uniq_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_create_of_sec_index"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"6. Hit crash point after data is updated to system-table and" -" in-memory dict." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_on_updating_dict_sys_info"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -"7. Hit crash point before/after log checkpoint is done." -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_before_log_removal"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -use test; -set global innodb_file_per_table = 1; -SET innodb_strict_mode=OFF; -create table t ( -i int, f float, c char, -primary key pk(i), unique findex(f), index ck(c)) -engine = innodb row_format = compressed -key_block_size = 8; -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -check table t; -Table Op Msg_type Msg_text -test.t check status OK -set session debug = "+d,ib_trunc_crash_after_truncate_done"; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -truncate table t; -ERROR HY000: Lost connection to MySQL server during query -check table t; -Table Op Msg_type Msg_text -test.t check status OK -select * from t; -i f c -insert into t values (1, 1.1, 'a'), (2, 2.2, 'b'), (3, 3.3, 'c'); -select * from t; -i f c -1 1.1 a -2 2.2 b -3 3.3 c -select * from t where f < 2.5; -i f c -1 1.1 a -2 2.2 b -drop table t; -set global innodb_file_per_table = 1; diff --git a/mysql-test/suite/innodb_zip/r/wl6501_scale_1.result b/mysql-test/suite/innodb_zip/r/wl6501_scale_1.result deleted file mode 100644 index 3a74b6ebc11..00000000000 --- a/mysql-test/suite/innodb_zip/r/wl6501_scale_1.result +++ /dev/null @@ -1,345 +0,0 @@ -set innodb_strict_mode=OFF; -create procedure populate() -begin -declare i int default 1; -while (i <= 5000) do -insert into t1 values (i, 'a', 'b'); -insert into t2 values (i, 'a', 'b'); -insert into t3 values (i, 'a', 'b'); -set i = i + 1; -end while; -end| -create procedure populate_small() -begin -declare i int default 10001; -while (i <= 12000) do -insert into t1 values (i, 'c', 'd'); -insert into t2 values (i, 'a', 'b'); -insert into t3 values (i, 'a', 'b'); -set i = i + 1; -end while; -end| -set global innodb_file_per_table = 1; -create table tNUMBER -(i int, cNUMBER char(NUMBER), cNUMBER char(NUMBER), -index cNUMBER_idx(cNUMBER)) -engine=innodb row_format=compact -key_block_size=NUMBER; -Warnings: -Warning NUMBER InnoDB: ignoring KEY_BLOCK_SIZE=NUMBER unless ROW_FORMAT=COMPRESSED. -create table t2 -(i int, c1 char(100), c2 char(100), -index c1_idx(c1)) -engine=innodb row_format=compact -key_block_size=16; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16 unless ROW_FORMAT=COMPRESSED. -create temporary table t3 -(i int, c1 char(100), c2 char(100), -index c1_idx(c1)) -engine=innodb row_format=compact -key_block_size=16; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE is ignored for TEMPORARY TABLE. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16. -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -begin; -call populate(); -commit; -select count(*) from t1; -count(*) -5000 -select count(*) from t2; -count(*) -5000 -select count(*) from t3; -count(*) -5000 -truncate table t1; -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -5000 -select count(*) from t3; -count(*) -5000 -call populate_small(); -select count(*) from t1; -count(*) -2000 -select count(*) from t2; -count(*) -7000 -select count(*) from t3; -count(*) -7000 -truncate table t2; -truncate table t3; -select count(*) from t1; -count(*) -2000 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -call populate_small(); -select count(*) from t1; -count(*) -4000 -select count(*) from t2; -count(*) -2000 -select count(*) from t3; -count(*) -2000 -drop table t1; -drop table t2; -drop table t3; -drop procedure populate; -drop procedure populate_small; -set global innodb_file_format = Barracuda; -Warnings: -Warning 131 Using innodb_file_format is deprecated and the parameter may be removed in future releases. See https://mariadb.com/kb/en/library/xtradbinnodb-file-format/ -set global innodb_file_per_table = 1; -set innodb_strict_mode=OFF; -create procedure populate() -begin -declare i int default 1; -while (i <= 5000) do -insert into t1 values (i, 'a', 'b'); -insert into t2 values (i, 'a', 'b'); -insert into t3 values (i, 'a', 'b'); -set i = i + 1; -end while; -end| -create procedure populate_small() -begin -declare i int default 10001; -while (i <= 12000) do -insert into t1 values (i, 'c', 'd'); -insert into t2 values (i, 'a', 'b'); -insert into t3 values (i, 'a', 'b'); -set i = i + 1; -end while; -end| -set global innodb_file_per_table = 1; -create table tNUMBER -(i int, cNUMBER char(NUMBER), cNUMBER char(NUMBER), -index cNUMBER_idx(cNUMBER)) -engine=innodb row_format=compressed -key_block_size=NUMBER; -create table t2 -(i int, c1 char(100), c2 char(100), -index c1_idx(c1)) -engine=innodb row_format=compressed -key_block_size=16; -create temporary table t3 -(i int, c1 char(100), c2 char(100), -index c1_idx(c1)) -engine=innodb row_format=compressed -key_block_size=16; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE is ignored for TEMPORARY TABLE. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16. -Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED is ignored for TEMPORARY TABLE. -Warning 1478 InnoDB: assuming ROW_FORMAT=DYNAMIC. -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -begin; -call populate(); -commit; -select count(*) from t1; -count(*) -5000 -select count(*) from t2; -count(*) -5000 -select count(*) from t3; -count(*) -5000 -truncate table t1; -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -5000 -select count(*) from t3; -count(*) -5000 -call populate_small(); -select count(*) from t1; -count(*) -2000 -select count(*) from t2; -count(*) -7000 -select count(*) from t3; -count(*) -7000 -truncate table t2; -truncate table t3; -select count(*) from t1; -count(*) -2000 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -call populate_small(); -select count(*) from t1; -count(*) -4000 -select count(*) from t2; -count(*) -2000 -select count(*) from t3; -count(*) -2000 -drop table t1; -drop table t2; -drop table t3; -drop procedure populate; -drop procedure populate_small; -set global innodb_file_format = Barracuda; -Warnings: -Warning 131 Using innodb_file_format is deprecated and the parameter may be removed in future releases. See https://mariadb.com/kb/en/library/xtradbinnodb-file-format/ -set global innodb_file_per_table = 1; -set innodb_strict_mode=OFF; -create procedure populate() -begin -declare i int default 1; -while (i <= 5000) do -insert into t1 values (i, 'a', 'b'); -insert into t2 values (i, 'a', 'b'); -insert into t3 values (i, 'a', 'b'); -set i = i + 1; -end while; -end| -create procedure populate_small() -begin -declare i int default 10001; -while (i <= 12000) do -insert into t1 values (i, 'c', 'd'); -insert into t2 values (i, 'a', 'b'); -insert into t3 values (i, 'a', 'b'); -set i = i + 1; -end while; -end| -set global innodb_file_per_table = 0; -create table tNUMBER -(i int, cNUMBER char(NUMBER), cNUMBER char(NUMBER), -index cNUMBER_idx(cNUMBER)) -engine=innodb row_format=compact -key_block_size=NUMBER; -Warnings: -Warning NUMBER InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Warning NUMBER InnoDB: ignoring KEY_BLOCK_SIZE=NUMBER. -create table t2 -(i int, c1 char(100), c2 char(100), -index c1_idx(c1)) -engine=innodb row_format=compact -key_block_size=16; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16. -create temporary table t3 -(i int, c1 char(100), c2 char(100), -index c1_idx(c1)) -engine=innodb row_format=compact -key_block_size=16; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE is ignored for TEMPORARY TABLE. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=16. -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -begin; -call populate(); -commit; -select count(*) from t1; -count(*) -5000 -select count(*) from t2; -count(*) -5000 -select count(*) from t3; -count(*) -5000 -truncate table t1; -select count(*) from t1; -count(*) -0 -select count(*) from t2; -count(*) -5000 -select count(*) from t3; -count(*) -5000 -call populate_small(); -select count(*) from t1; -count(*) -2000 -select count(*) from t2; -count(*) -7000 -select count(*) from t3; -count(*) -7000 -truncate table t2; -truncate table t3; -select count(*) from t1; -count(*) -2000 -select count(*) from t2; -count(*) -0 -select count(*) from t3; -count(*) -0 -call populate_small(); -select count(*) from t1; -count(*) -4000 -select count(*) from t2; -count(*) -2000 -select count(*) from t3; -count(*) -2000 -drop table t1; -drop table t2; -drop table t3; -drop procedure populate; -drop procedure populate_small; -set global innodb_file_format = Barracuda; -Warnings: -Warning 131 Using innodb_file_format is deprecated and the parameter may be removed in future releases. See https://mariadb.com/kb/en/library/xtradbinnodb-file-format/ -set global innodb_file_per_table = 1; diff --git a/mysql-test/suite/innodb_zip/t/wl6501_1.test b/mysql-test/suite/innodb_zip/t/wl6501_1.test deleted file mode 100644 index dd8b5f65b31..00000000000 --- a/mysql-test/suite/innodb_zip/t/wl6501_1.test +++ /dev/null @@ -1,451 +0,0 @@ - -#################################################################### -# TC to check truncate table statement atomicity for single # -# tablespace # -# Sceanrio covered: # -# 1. Debug points added for worklog # -# 2. Table with differnt row types # -# 3. Transactional statement. # -#################################################################### - - ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/big_test.inc ---source include/have_innodb_16k.inc - -# Valgrind would result in a "long semaphore wait" inside InnoDB ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - -#----------------------------------------------------------------------- ---disable_query_log -let $MYSQL_DATA_DIR= `select @@datadir`; -let $data_directory = data directory='$MYSQL_TMP_DIR/alt_dir'; -let $innodb_file_per_table_orig=`select @@innodb_file_per_table`; - -call mtr.add_suppression("InnoDB.*table did not exist in the InnoDB data dictionary.*"); -call mtr.add_suppression("InnoDB: A page in the doublewrite buffer is not within space bounds.*"); -call mtr.add_suppression("InnoDB: Cannot create file.*"); -call mtr.add_suppression("InnoDB: Error number 17 means 'File exists'.*"); -call mtr.add_suppression("InnoDB: A page in the doublewrite buffer is not within space bounds"); -call mtr.add_suppression("InnoDB: Error: table .* does not exist in the InnoDB internal"); ---enable_query_log - -#----------------------------------------------------------------------- -set global innodb_file_per_table=on; ---echo # Verify that 'TRUNCATE TABLE' statement works fine and the size ---echo # of .ibd file is equal to the initial size after truncation. - -#----------------------------------------------------------------------- -drop table if exists t1,t2,t3,t4,t6; -let $cnt = 6; -while ($cnt) { - - # table with basic data type + primary ,secondary,composite,prefix index - create table t1(c1 int not null, - c2 int not null, - c3 char(255) not null, - c4 text(500) not null, - c5 blob(500) not null, - c6 varchar(500) not null, - c7 varchar(500) not null, - c8 datetime, - c9 decimal(5,3), - primary key (c1), - index (c3,c4(50),c5(50)), - index (c2)) - engine=innodb row_format=redundant; - - - create table t2(c1 int not null, - c2 int not null, - c3 char(255) not null, - c4 text(500) not null, - c5 blob(500) not null, - c6 varchar(500) not null, - c7 varchar(500) not null, - c8 datetime, - c9 decimal(5,3), - primary key (c1), - index (c3,c4(50),c5(50)), - index (c2)) - engine=innodb row_format=compact; - - - # with row type , key block size = 4K - create table t3(c1 int not null, - c2 int not null, - c3 char(255) not null, - c4 text(500) not null, - c5 blob(500) not null, - c6 varchar(500) not null, - c7 varchar(500) not null, - c8 datetime, - c9 decimal(5,3), - primary key (c1), - index (c3,c4(50),c5(50)), - index (c2)) - engine=innodb row_format=compressed key_block_size=4; - - - create table t4(c1 int not null, - c2 int not null, - c3 char(255) not null, - c4 text(500) not null, - c5 blob(500) not null, - c6 varchar(500) not null, - c7 varchar(500) not null, - c8 datetime, - c9 decimal(5,3), - primary key (c1), - index (c3,c4(50),c5(50)), - index (c2)) - engine=innodb row_format=dynamic; - - - create temporary table t5(c1 int not null, - c2 int not null, - c3 char(255) not null, - c4 text(500) not null, - c5 blob(500) not null, - c6 varchar(500) not null, - c7 varchar(500) not null, - c8 datetime, - c9 decimal(5,3), - primary key (c1), - index (c3,c4(50),c5(50)), - index (c2)) - engine=innodb; - - create table t6 ( a int ) engine = innodb; - insert into t6 values (50),(100),(150); - - --disable_query_log - --disable_result_log - let $n=5; - - # load created tables. - while ($n) - { - start transaction; - - eval insert ignore into t1 values( - $n, $n, - repeat(concat(' tc3_',$n), 42), - repeat(concat(' tc4_',$n), 300), - repeat(concat(' tc5_',$n), 300), - repeat(concat(' tc6_',$n), 300), - repeat(concat(' tc7_',$n), 300), - now(), (100.55+$n)); - - eval insert ignore into t2 values( - $n, $n, - repeat(concat(' tc3_',$n), 42), - repeat(concat(' tc4_',$n), 300), - repeat(concat(' tc5_',$n), 300), - repeat(concat(' tc6_',$n), 300), - repeat(concat(' tc7_',$n), 300), - now(), (100.55+$n)); - - eval insert ignore into t3 values( - $n, $n, - repeat(concat(' tc3_',$n), 42), - repeat(concat(' tc4_',$n), 300), - repeat(concat(' tc5_',$n), 300), - repeat(concat(' tc6_',$n), 300), - repeat(concat(' tc7_',$n), 300), - now(), (100.55+$n)); - - eval insert ignore into t4 values( - $n, $n, - repeat(concat(' tc3_',$n), 42), - repeat(concat(' tc4_',$n), 300), - repeat(concat(' tc5_',$n), 300), - repeat(concat(' tc6_',$n), 300), - repeat(concat(' tc7_',$n), 300), - now(), (100.55+$n)); - - eval insert ignore into t5 values( - $n, $n, - repeat(concat(' tc3_',$n), 42), - repeat(concat(' tc4_',$n), 300), - repeat(concat(' tc5_',$n), 300), - repeat(concat(' tc6_',$n), 300), - repeat(concat(' tc7_',$n), 300), - now(), (100.55+$n)); - - if ($n <= 3) - { - commit; - } - - if ($n > 3) - { - rollback; - } - - dec $n; - } - - # validate loading of the tables. - --enable_result_log - --enable_query_log - select count(*) from t1; - select count(*) from t2; - select count(*) from t3; - select count(*) from t4; - select count(*) from t5; - select count(*) from t6; - - # set the debug crash point and exercise them. - if ($cnt == 6) - { - set session debug="+d,ib_trunc_crash_during_drop_index_temp_table"; - --echo "---debug ib_trunc_crash_during_drop_index_temp_table point---" - } - if ($cnt == 5) - { - set session debug="+d,ib_trunc_crash_drop_reinit_done_create_to_start"; - --echo "---debug ib_trunc_crash_drop_reinit_done_create_to_start---" - } - - if ($cnt >= 5) { - --echo # Write file to make mysql-test-run.pl expect crash and restart - --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --echo # Run the crashing query - --error 2013 - truncate table t5; - --source include/wait_until_disconnected.inc - --enable_reconnect - --echo # Restart the MySQL server - --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --source include/wait_until_connected_again.inc - --disable_reconnect - select count(*) from t1; - select count(*) from t2; - select count(*) from t3; - select count(*) from t4; - --error ER_NO_SUCH_TABLE - select count(*) from t5; - select count(*) from t6; - } - - # set the debug crash point and exercise them. - if ($cnt == 6) - { - set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; - --echo "---debug ib_trunc_crash_on_drop_of_sec_index point---" - } - if ($cnt == 5) - { - set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; - --echo "---debug ib_trunc_crash_on_create_of_sec_index---" - } - if ($cnt == 4) - { - set session debug="+d,ib_trunc_crash_before_log_removal"; - --echo "---debug ib_trunc_crash_before_log_removal point---" - } - if ($cnt == 3) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 2) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 1) - { - set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; - --echo "---debug ib_trunc_crash_after_redo_log_write_complete point---" - } - - --echo # Write file to make mysql-test-run.pl expect crash and restart - --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --echo # Run the crashing query - --error 2013 - truncate table t1; - --source include/wait_until_disconnected.inc - --enable_reconnect - --echo # Restart the MySQL server - --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --source include/wait_until_connected_again.inc - --disable_reconnect - select count(*) from t1; - select count(*) from t2; - select count(*) from t3; - select count(*) from t4; - --error ER_NO_SUCH_TABLE - select count(*) from t5; - select count(*) from t6; - - if ($cnt == 6) - { - set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; - --echo "---debug ib_trunc_crash_on_drop_of_sec_index point---" - } - if ($cnt == 5) - { - set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; - --echo "---debug ib_trunc_crash_on_create_of_sec_index---" - } - if ($cnt == 4) - { - set session debug="+d,ib_trunc_crash_before_log_removal"; - --echo "---debug ib_trunc_crash_before_log_removal point---" - } - if ($cnt == 3) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 2) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 1) - { - set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; - --echo "---debug ib_trunc_crash_after_redo_log_write_complete point---" - } - - - --echo # Write file to make mysql-test-run.pl expect crash and restart - --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --echo # Run the crashing query - --error 2013 - truncate table t2; - --source include/wait_until_disconnected.inc - --enable_reconnect - --echo # Restart the MySQL server - --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --source include/wait_until_connected_again.inc - --disable_reconnect - select count(*) from t1; - select count(*) from t2; - select count(*) from t3; - select count(*) from t4; - --error ER_NO_SUCH_TABLE - select count(*) from t5; - select count(*) from t6; - - if ($cnt == 6) - { - set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; - --echo "---debug ib_trunc_crash_on_drop_of_sec_index point---" - } - if ($cnt == 5) - { - set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; - --echo "---debug ib_trunc_crash_on_create_of_sec_index---" - } - if ($cnt == 4) - { - set session debug="+d,ib_trunc_crash_before_log_removal"; - --echo "---debug ib_trunc_crash_before_log_removal point---" - } - if ($cnt == 3) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 2) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 1) - { - set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; - --echo "---debug ib_trunc_crash_after_redo_log_write_complete point---" - } - - - --echo # Write file to make mysql-test-run.pl expect crash and restart - --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --echo # Run the crashing query - --error 2013 - truncate table t3; - --source include/wait_until_disconnected.inc - --enable_reconnect - --echo # Restart the MySQL server - --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --source include/wait_until_connected_again.inc - --disable_reconnect - select count(*) from t1; - select count(*) from t2; - select count(*) from t3; - select count(*) from t4; - --error ER_NO_SUCH_TABLE - select count(*) from t5; - select count(*) from t6; - - - if ($cnt == 6) - { - set session debug="+d,ib_trunc_crash_on_drop_of_sec_index"; - --echo "---debug ib_trunc_crash_on_drop_of_sec_index point---" - } - if ($cnt == 5) - { - set session debug="+d,ib_trunc_crash_on_create_of_sec_index"; - --echo "---debug ib_trunc_crash_on_create_of_sec_index---" - } - if ($cnt == 4) - { - set session debug="+d,ib_trunc_crash_before_log_removal"; - --echo "---debug ib_trunc_crash_before_log_removal point---" - } - if ($cnt == 3) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 2) - { - set session debug="+d,ib_trunc_crash_after_truncate_done"; - --echo "---debug ib_trunc_crash_after_truncate_done point---" - } - if ($cnt == 1) - { - set session debug="+d,ib_trunc_crash_after_redo_log_write_complete"; - --echo "---debug ib_trunc_crash_after_redo_log_write_complete point---" - } - - --echo # Write file to make mysql-test-run.pl expect crash and restart - --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --echo # Run the crashing query - --error 2013 - truncate table t4; - --source include/wait_until_disconnected.inc - --enable_reconnect - --echo # Restart the MySQL server - --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - --source include/wait_until_connected_again.inc - --disable_reconnect - select count(*) from t1; - select count(*) from t2; - select count(*) from t3; - select count(*) from t4; - --error ER_NO_SUCH_TABLE - select count(*) from t5; - select count(*) from t6; - - drop table t1, t2, t3, t4, t6; - - dec $cnt; - - --disable_query_log - eval set global innodb_file_per_table=$innodb_file_per_table_orig; - --enable_query_log -} - - - diff --git a/mysql-test/suite/innodb_zip/t/wl6501_crash_3.test b/mysql-test/suite/innodb_zip/t/wl6501_crash_3.test deleted file mode 100644 index 3ec990b4715..00000000000 --- a/mysql-test/suite/innodb_zip/t/wl6501_crash_3.test +++ /dev/null @@ -1,25 +0,0 @@ -# -# WL#6501: make truncate table atomic -# - -# TC tries to hit crash point during truncate of -# compressed non-temp table residing in single tablespace -# with page-size=16k - ---source include/have_innodb.inc ---source include/have_innodb_16k.inc ---source include/have_debug.inc ---source include/big_test.inc - -# Valgrind would complain about memory leaks when we crash on purpose. ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - -let $wl6501_file_per_table = 1; -let $wl6501_row_fmt = compressed; -let $wl6501_kbs = 16; ---source suite/innodb/include/innodb_wl6501_crash.inc - diff --git a/mysql-test/suite/innodb_zip/t/wl6501_crash_4.test b/mysql-test/suite/innodb_zip/t/wl6501_crash_4.test deleted file mode 100644 index f54df3c128c..00000000000 --- a/mysql-test/suite/innodb_zip/t/wl6501_crash_4.test +++ /dev/null @@ -1,27 +0,0 @@ -# -# WL#6501: make truncate table atomic -# - -# TC tries to hit crash point during truncate of -# compressed non-temp table residing in single tablespace. -# with page-size=4k - ---source include/have_innodb.inc ---source include/have_innodb_4k.inc ---source include/have_debug.inc ---source include/big_test.inc - -# Valgrind would complain about memory leaks when we crash on purpose. ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - -let $wl6501_file_per_table = 1; -let $wl6501_row_fmt = compressed; -let $wl6501_kbs = 4; ---source suite/innodb/include/innodb_wl6501_crash.inc - -let $wl6501_temp = temporary; ---source suite/innodb/include/innodb_wl6501_crash_temp.inc diff --git a/mysql-test/suite/innodb_zip/t/wl6501_crash_5.test b/mysql-test/suite/innodb_zip/t/wl6501_crash_5.test deleted file mode 100644 index 2f9847ae5fb..00000000000 --- a/mysql-test/suite/innodb_zip/t/wl6501_crash_5.test +++ /dev/null @@ -1,25 +0,0 @@ -# -# WL#6501: make truncate table atomic -# - -# TC tries to hit crash point during truncate of -# compressed non-temp table residing in single tablespace. -# with page-size=8k - ---source include/have_innodb.inc ---source include/have_innodb_8k.inc ---source include/have_debug.inc ---source include/big_test.inc - -# Valgrind would complain about memory leaks when we crash on purpose. ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - -let $wl6501_file_per_table = 1; -let $wl6501_row_fmt = compressed; -let $wl6501_kbs = 8; ---source suite/innodb/include/innodb_wl6501_crash.inc - diff --git a/mysql-test/suite/innodb_zip/t/wl6501_scale_1.test b/mysql-test/suite/innodb_zip/t/wl6501_scale_1.test deleted file mode 100644 index e6392759d5e..00000000000 --- a/mysql-test/suite/innodb_zip/t/wl6501_scale_1.test +++ /dev/null @@ -1,37 +0,0 @@ -# -# WL#6501: make truncate table atomic -# - -# load table with some significiant amount of data -# and then try truncate - ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/big_test.inc ---source include/have_innodb_16k.inc - -# Valgrind would complain about memory leaks when we crash on purpose. ---source include/not_valgrind.inc -# Embedded server does not support crashing ---source include/not_embedded.inc -# Avoid CrashReporter popup on Mac ---source include/not_crashrep.inc - - -# Single-Tablespace/Non-Compressed -let $wl6501_file_per_table = 1; -let $wl6501_row_fmt = compact; -let $wl6501_kbs = 16; ---source suite/innodb_zip/include/innodb_wl6501_scale.inc - -# Single-Tablespace/Compressed -let $wl6501_file_per_table = 1; -let $wl6501_row_fmt = compressed; -let $wl6501_kbs = 16; ---source suite/innodb_zip/include/innodb_wl6501_scale.inc - -# System-Tablespace/Non-Compressed -let $wl6501_file_per_table = 0; -let $wl6501_row_fmt = compact; -let $wl6501_kbs = 16; ---source suite/innodb_zip/include/innodb_wl6501_scale.inc diff --git a/mysql-test/suite/mariabackup/truncate_during_backup.test b/mysql-test/suite/mariabackup/truncate_during_backup.test index c01a74588e7..46ee244dfb0 100644 --- a/mysql-test/suite/mariabackup/truncate_during_backup.test +++ b/mysql-test/suite/mariabackup/truncate_during_backup.test @@ -7,7 +7,6 @@ CREATE TABLE t1 ENGINE=InnoDB SELECT 1; --let after_load_tablespaces=TRUNCATE test.t1 --disable_result_log ---error 1 exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --dbug=+d,mariabackup_events; --enable_result_log diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 2a0ac9a465f..c933ad4a0ab 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -402,6 +402,8 @@ rpl_slave_state::truncate_state_table(THD *thd) NULL, TL_WRITE); if (!(err= open_and_lock_tables(thd, &tlist, FALSE, 0))) { + tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED, "mysql", + rpl_gtid_slave_state_table_name.str, false); err= tlist.table->file->ha_truncate(); if (err) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index f6a325a15fb..ab531dc775d 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -563,7 +563,8 @@ buf_dblwr_process() is scheduled for truncation or was truncated and we have parsed an MLOG_TRUNCATE record. */ if (!srv_is_tablespace_truncated(space_id) - && !srv_was_tablespace_truncated(space)) { + && !srv_was_tablespace_truncated(space) + && !srv_is_undo_tablespace(space_id)) { ib::warn() << "A copy of page " << page_id << " in the doublewrite buffer slot " << page_no_dblwr diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 74e3bd57452..9c652687f72 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -560,13 +560,15 @@ the list as they age towards the tail of the LRU. @param[in] id tablespace identifier @param[in] observer flush observer (to check for interrupt), or NULL if the files should not be written to -@return whether all dirty pages were freed */ +@param[in] first first page to be flushed or evicted +@return whether all matching dirty pages were removed */ static MY_ATTRIBUTE((warn_unused_result)) bool buf_flush_or_remove_pages( buf_pool_t* buf_pool, ulint id, - FlushObserver* observer) + FlushObserver* observer, + ulint first) { buf_page_t* prev; buf_page_t* bpage; @@ -607,6 +609,8 @@ rescan: } else if (id != bpage->id.space()) { /* Skip this block, because it is for a different tablespace. */ + } else if (bpage->id.page_no() < first) { + /* Skip this block, because it is below the limit. */ } else if (!buf_flush_or_remove_page( buf_pool, bpage, observer != NULL)) { @@ -670,18 +674,20 @@ the tail of the LRU list. @param[in] id tablespace identifier @param[in] observer flush observer, or NULL if the files should not be written to -*/ +@param[in] first first page to be flushed or evicted */ static void buf_flush_dirty_pages( buf_pool_t* buf_pool, ulint id, - FlushObserver* observer) + FlushObserver* observer, + ulint first) { for (;;) { buf_pool_mutex_enter(buf_pool); - bool freed = buf_flush_or_remove_pages(buf_pool, id, observer); + bool freed = buf_flush_or_remove_pages(buf_pool, id, observer, + first); buf_pool_mutex_exit(buf_pool); @@ -696,20 +702,24 @@ buf_flush_dirty_pages( } ut_ad((observer && observer->is_interrupted()) + || first || buf_pool_get_dirty_pages_count(buf_pool, id, observer) == 0); } /** Empty the flush list for all pages belonging to a tablespace. @param[in] id tablespace identifier @param[in] observer flush observer, - or NULL if nothing is to be written */ -void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer) + or NULL if nothing is to be written +@param[in] first first page to be flushed or evicted */ +void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer, + ulint first) { /* Pages in the system tablespace must never be discarded. */ ut_ad(id || observer); for (ulint i = 0; i < srv_buf_pool_instances; i++) { - buf_flush_dirty_pages(buf_pool_from_array(i), id, observer); + buf_flush_dirty_pages(buf_pool_from_array(i), id, observer, + first); } if (observer && !observer->is_interrupted()) { diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 598da3ff706..4c4f6292a53 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2017, MariaDB Corporation. +Copyright (c) 2015, 2018, MariaDB Corporation. 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 @@ -176,17 +176,6 @@ buf_read_page_low( dst = ((buf_block_t*) bpage)->frame; } - DBUG_EXECUTE_IF( - "innodb_invalid_read_after_truncate", - if (fil_space_t* space = fil_space_acquire(page_id.space())) { - if (!strcmp(space->name, "test/t1") - && page_id.page_no() == space->size - 1) { - type = 0; - sync = true; - } - fil_space_release(space); - }); - IORequest request(type | IORequest::READ); *err = fil_io( @@ -332,19 +321,6 @@ buf_read_ahead_random( that is, reside near the start of the LRU list. */ for (i = low; i < high; i++) { - DBUG_EXECUTE_IF( - "innodb_invalid_read_after_truncate", - if (fil_space_t* space = fil_space_acquire( - page_id.space())) { - bool skip = !strcmp(space->name, "test/t1"); - fil_space_release(space); - if (skip) { - high = space->size; - buf_pool_mutex_exit(buf_pool); - goto read_ahead; - } - }); - const buf_page_t* bpage = buf_page_hash_get( buf_pool, page_id_t(page_id.space(), i)); diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index a83ee896972..91d979d4ee5 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -1161,73 +1161,6 @@ dict_recreate_index_tree( return(FIL_NULL); } -/*******************************************************************//** -Truncates the index tree but don't update SYSTEM TABLES. -@return DB_SUCCESS or error */ -dberr_t -dict_truncate_index_tree_in_mem( -/*============================*/ - dict_index_t* index) /*!< in/out: index */ -{ - mtr_t mtr; - bool truncate; - ulint space = index->space; - - ut_ad(mutex_own(&dict_sys->mutex)); - ut_ad(dict_table_is_temporary(index->table)); - - ulint type = index->type; - ulint root_page_no = index->page; - - if (root_page_no == FIL_NULL) { - - /* The tree has been freed. */ - ib::warn() << "Trying to TRUNCATE a missing index of table " - << index->table->name << "!"; - - truncate = false; - } else { - truncate = true; - } - - bool found; - const page_size_t page_size(fil_space_get_page_size(space, - &found)); - - if (!found) { - - /* It is a single table tablespace and the .ibd file is - missing: do nothing */ - - ib::warn() - << "Trying to TRUNCATE a missing .ibd file of table " - << index->table->name << "!"; - } - - /* If table to truncate resides in its on own tablespace that will - be re-created on truncate then we can ignore freeing of existing - tablespace objects. */ - - if (truncate) { - btr_free(page_id_t(space, root_page_no), page_size); - } - - mtr_start(&mtr); - mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); - - root_page_no = btr_create( - type, space, page_size, index->id, index, NULL, &mtr); - - DBUG_EXECUTE_IF("ib_err_trunc_temp_recreate_index", - root_page_no = FIL_NULL;); - - index->page = root_page_no; - - mtr_commit(&mtr); - - return(index->page == FIL_NULL ? DB_ERROR : DB_SUCCESS); -} - /*********************************************************************//** Creates a table create graph. @return own: table create node */ @@ -1677,16 +1610,11 @@ dict_create_or_check_foreign_constraint_tables(void) /* Check which incomplete table definition to drop. */ if (sys_foreign_err == DB_CORRUPTION) { - ib::warn() << "Dropping incompletely created" - " SYS_FOREIGN table."; - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE); + row_drop_table_after_create_fail("SYS_FOREIGN", trx); } if (sys_foreign_cols_err == DB_CORRUPTION) { - ib::warn() << "Dropping incompletely created" - " SYS_FOREIGN_COLS table."; - - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE); + row_drop_table_after_create_fail("SYS_FOREIGN_COLS", trx); } ib::info() << "Creating foreign key constraint system tables."; @@ -1738,8 +1666,8 @@ dict_create_or_check_foreign_constraint_tables(void) ut_ad(err == DB_OUT_OF_FILE_SPACE || err == DB_TOO_MANY_CONCURRENT_TRXS); - row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE); - row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE); + row_drop_table_after_create_fail("SYS_FOREIGN", trx); + row_drop_table_after_create_fail("SYS_FOREIGN_COLS", trx); if (err == DB_OUT_OF_FILE_SPACE) { err = DB_MUST_GET_MORE_FILE_SPACE; @@ -1807,9 +1735,7 @@ dict_create_or_check_sys_virtual() /* Check which incomplete table definition to drop. */ if (err == DB_CORRUPTION) { - ib::warn() << "Dropping incompletely created" - " SYS_VIRTUAL table."; - row_drop_table_for_mysql("SYS_VIRTUAL", trx, false, TRUE); + row_drop_table_after_create_fail("SYS_VIRTUAL", trx); } ib::info() << "Creating sys_virtual system tables."; @@ -1843,7 +1769,7 @@ dict_create_or_check_sys_virtual() ut_ad(err == DB_OUT_OF_FILE_SPACE || err == DB_TOO_MANY_CONCURRENT_TRXS); - row_drop_table_for_mysql("SYS_VIRTUAL", trx, false, TRUE); + row_drop_table_after_create_fail("SYS_VIRTUAL", trx); if (err == DB_OUT_OF_FILE_SPACE) { err = DB_MUST_GET_MORE_FILE_SPACE; @@ -2462,16 +2388,11 @@ dict_create_or_check_sys_tablespace(void) /* Check which incomplete table definition to drop. */ if (sys_tablespaces_err == DB_CORRUPTION) { - ib::warn() << "Dropping incompletely created" - " SYS_TABLESPACES table."; - row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE); + row_drop_table_after_create_fail("SYS_TABLESPACES", trx); } if (sys_datafiles_err == DB_CORRUPTION) { - ib::warn() << "Dropping incompletely created" - " SYS_DATAFILES table."; - - row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE); + row_drop_table_after_create_fail("SYS_DATAFILES", trx); } ib::info() << "Creating tablespace and datafile system tables."; @@ -2506,8 +2427,8 @@ dict_create_or_check_sys_tablespace(void) || err == DB_DUPLICATE_KEY || err == DB_TOO_MANY_CONCURRENT_TRXS); - row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE); - row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE); + row_drop_table_after_create_fail("SYS_TABLESPACES", trx); + row_drop_table_after_create_fail("SYS_DATAFILES", trx); if (err == DB_OUT_OF_FILE_SPACE) { err = DB_MUST_GET_MORE_FILE_SPACE; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 3c9640c8e15..6c32531a07e 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -943,8 +943,8 @@ fil_crypt_read_crypt_data(fil_space_t* space) /* The encryption metadata has already been read, or the tablespace is not encrypted and the file has been opened already, or the file cannot be accessed, - likely due to a concurrent TRUNCATE or - RENAME or DROP (possibly as part of ALTER TABLE). + likely due to a concurrent DROP + (possibly as part of TRUNCATE or ALTER TABLE). FIXME: The file can become unaccessible any time after this check! We should really remove this function and instead make crypt_data an integral @@ -1628,7 +1628,7 @@ fil_crypt_get_page_throttle_func( ut_ad(space->n_pending_ops > 0); /* Before reading from tablespace we need to make sure that - the tablespace is not about to be dropped or truncated. */ + the tablespace is not about to be dropped. */ if (space->is_stopping()) { return NULL; } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index feebe5d2162..386493eef18 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2246,13 +2246,14 @@ fil_op_write_log( byte* log_ptr; ulint len; - ut_ad(first_page_no == 0); + ut_ad(first_page_no == 0 || type == MLOG_FILE_CREATE2); ut_ad(fsp_flags_is_valid(flags, space_id)); /* fil_name_parse() requires that there be at least one path separator and that the file path end with ".ibd". */ ut_ad(strchr(path, OS_PATH_SEPARATOR) != NULL); - ut_ad(strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD) == 0); + ut_ad(first_page_no /* trimming an undo tablespace */ + || !strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD)); log_ptr = mlog_open(mtr, 11 + 4 + 2 + 1); @@ -2685,7 +2686,7 @@ fil_op_replay_rename( enum fil_operation_t { FIL_OPERATION_DELETE, /*!< delete a single-table tablespace */ FIL_OPERATION_CLOSE, /*!< close a single-table tablespace */ - FIL_OPERATION_TRUNCATE /*!< truncate a single-table tablespace */ + FIL_OPERATION_TRUNCATE /*!< truncate an undo tablespace */ }; /** Check for pending operations. @@ -2819,8 +2820,6 @@ fil_check_pending_operations( /* Check for pending IO. */ - *path = 0; - for (;;) { sp = fil_space_get_by_id(id); @@ -2833,7 +2832,7 @@ fil_check_pending_operations( count = fil_check_pending_io(operation, sp, &node, count); - if (count == 0) { + if (count == 0 && path) { *path = mem_strdup(node->name); } @@ -2921,7 +2920,8 @@ fil_close_tablespace( not (necessarily) protected by meta-data locks. (Rollback would generally be protected, but rollback of FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks -but only by InnoDB table locks, which may be broken by TRUNCATE TABLE.) +but only by InnoDB table locks, which may be broken by +lock_remove_all_on_table().) @param[in] table persistent table checked @return whether the table is accessible */ bool @@ -2937,8 +2937,6 @@ fil_table_accessible(const dict_table_t* table) ut_ad(accessible || dict_table_is_file_per_table(table)); return(accessible); } else { - /* The tablespace may momentarily be missing during - TRUNCATE TABLE. */ return(false); } } @@ -3068,152 +3066,33 @@ fil_delete_tablespace( return(err); } -/** Truncate the tablespace to needed size. -@param[in] space_id id of tablespace to truncate -@param[in] size_in_pages truncate size. -@return true if truncate was successful. */ -bool -fil_truncate_tablespace( - ulint space_id, - ulint size_in_pages) +/** Prepare to truncate an undo tablespace. +@param[in] space_id undo tablespace id +@return the tablespace +@retval NULL if tablespace not found */ +fil_space_t* fil_truncate_prepare(ulint space_id) { - /* Step-1: Prepare tablespace for truncate. This involves - stopping all the new operations + IO on that tablespace - and ensuring that related pages are flushed to disk. */ - if (fil_prepare_for_truncate(space_id) != DB_SUCCESS) { - return(false); + /* Stop all I/O on the tablespace and ensure that related + pages are flushed to disk. */ + fil_space_t* space; + if (fil_check_pending_operations(space_id, FIL_OPERATION_TRUNCATE, + &space, NULL) != DB_SUCCESS) { + return NULL; } - - /* Step-2: Invalidate buffer pool pages belonging to the tablespace - to re-create. Remove all insert buffer entries for the tablespace */ - buf_LRU_flush_or_remove_pages(space_id, NULL); - - /* Step-3: Truncate the tablespace and accordingly update - the fil_space_t handler that is used to access this tablespace. */ - mutex_enter(&fil_system->mutex); - fil_space_t* space = fil_space_get_by_id(space_id); - - /* The following code must change when InnoDB supports - multiple datafiles per tablespace. */ - ut_a(UT_LIST_GET_LEN(space->chain) == 1); - - fil_node_t* node = UT_LIST_GET_FIRST(space->chain); - - ut_ad(node->is_open()); - - space->size = node->size = size_in_pages; - - bool success = os_file_truncate(node->name, node->handle, 0); - if (success) { - - os_offset_t size = os_offset_t(size_in_pages) * UNIV_PAGE_SIZE; - - success = os_file_set_size( - node->name, node->handle, size, - FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags)); - - if (success) { - space->stop_new_ops = false; - space->is_being_truncated = false; - } - } - - mutex_exit(&fil_system->mutex); - - return(success); + ut_ad(space != NULL); + return space; } -/*******************************************************************//** -Prepare for truncating a single-table tablespace. -1) Check pending operations on a tablespace; -2) Remove all insert buffer entries for the tablespace; -@return DB_SUCCESS or error */ -dberr_t -fil_prepare_for_truncate( -/*=====================*/ - ulint id) /*!< in: space id */ +/** Write log about an undo tablespace truncate operation. */ +void fil_truncate_log(fil_space_t* space, ulint size, mtr_t* mtr) { - char* path = 0; - fil_space_t* space = 0; - - ut_a(!is_system_tablespace(id)); - - dberr_t err = fil_check_pending_operations( - id, FIL_OPERATION_TRUNCATE, &space, &path); - - ut_free(path); - - if (err == DB_TABLESPACE_NOT_FOUND) { - ib::error() << "Cannot truncate tablespace " << id - << " because it is not found in the tablespace" - " memory cache."; - } - - return(err); -} - -/** Reinitialize the original tablespace header with the same space id -for single tablespace -@param[in] table table belongs to tablespace -@param[in] size size in blocks -@param[in] trx Transaction covering truncate */ -void -fil_reinit_space_header_for_table( - dict_table_t* table, - ulint size, - trx_t* trx) -{ - ulint id = table->space; - - ut_a(!is_system_tablespace(id)); - - /* Invalidate in the buffer pool all pages belonging - to the tablespace. The buffer pool scan may take long - time to complete, therefore we release dict_sys->mutex - and the dict operation lock during the scan and aquire - it again after the buffer pool scan.*/ - - /* Release the lock on the indexes too. So that - they won't violate the latch ordering. */ - dict_table_x_unlock_indexes(table); - row_mysql_unlock_data_dictionary(trx); - - /* Lock the search latch in shared mode to prevent user - from disabling AHI during the scan */ - btr_search_s_lock_all(); - DEBUG_SYNC_C("buffer_pool_scan"); - buf_LRU_flush_or_remove_pages(id, NULL); - btr_search_s_unlock_all(); - - row_mysql_lock_data_dictionary(trx); - - dict_table_x_lock_indexes(table); - - /* Remove all insert buffer entries for the tablespace */ - ibuf_delete_for_discarded_space(id); - - mutex_enter(&fil_system->mutex); - - fil_space_t* space = fil_space_get_by_id(id); - - /* The following code must change when InnoDB supports - multiple datafiles per tablespace. */ - ut_a(UT_LIST_GET_LEN(space->chain) == 1); - - fil_node_t* node = UT_LIST_GET_FIRST(space->chain); - - space->size = node->size = size; - - mutex_exit(&fil_system->mutex); - - mtr_t mtr; - - mtr_start(&mtr); - mtr.set_named_space(id); - - fsp_header_init(id, size, &mtr); - - mtr_commit(&mtr); + /* Write a MLOG_FILE_CREATE2 record with the new size, so that + recovery and backup will ignore any preceding redo log records + for writing pages that are after the new end of the tablespace. */ + ut_ad(UT_LIST_GET_LEN(space->chain) == 1); + const fil_node_t* file = UT_LIST_GET_FIRST(space->chain); + fil_op_write_log(MLOG_FILE_CREATE2, space->id, size, file->name, + NULL, space->flags & ~FSP_FLAGS_MEM_MASK, mtr); } #ifdef UNIV_DEBUG @@ -5085,7 +4964,6 @@ fil_io( if (space->id != TRX_SYS_SPACE && UT_LIST_GET_LEN(space->chain) == 1 && (srv_is_tablespace_truncated(space->id) - || space->is_being_truncated || srv_was_tablespace_truncated(space)) && req_type.is_read()) { @@ -5766,7 +5644,7 @@ fil_space_validate_for_mtr_commit( fil_space_release() after mtr_commit(). This is why n_pending_ops should not be zero if stop_new_ops is set. */ ut_ad(!space->stop_new_ops - || space->is_being_truncated /* TRUNCATE sets stop_new_ops */ + || space->is_being_truncated /* fil_truncate_prepare() */ || space->n_pending_ops > 0); } #endif /* UNIV_DEBUG */ @@ -5992,7 +5870,6 @@ truncate_t::truncate( } space->stop_new_ops = false; - space->is_being_truncated = false; /* If we opened the file in this function, close it. */ if (!already_open) { @@ -6185,7 +6062,7 @@ fil_space_keyrotate_next( } /* Skip spaces that are being created by fil_ibd_create(), - or dropped or truncated. Note that rotation_list contains only + or dropped. Note that rotation_list contains only space->purpose == FIL_TYPE_TABLESPACE. */ while (space != NULL && (UT_LIST_GET_LEN(space->chain) == 0 diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index d4d5abeb32f..6ddcff7a55a 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -639,7 +639,6 @@ fsp_space_modify_check( ut_ad(space->purpose == FIL_TYPE_TEMPORARY || space->purpose == FIL_TYPE_IMPORT || space->redo_skipped_count - || space->is_being_truncated || srv_is_tablespace_truncated(space->id)); return; case MTR_LOG_ALL: diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 81ec3a3c80e..8dd42c03f85 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1470,7 +1470,8 @@ fts_drop_table( /* Pass nonatomic=false (dont allow data dict unlock), because the transaction may hold locks on SYS_* tables from previous calls to fts_drop_table(). */ - error = row_drop_table_for_mysql(table_name, trx, true, false, false); + error = row_drop_table_for_mysql(table_name, trx, + SQLCOM_DROP_DB, false, false); if (error != DB_SUCCESS) { ib::error() << "Unable to drop FTS index aux table " @@ -1944,8 +1945,8 @@ func_exit: if (error != DB_SUCCESS) { for (it = common_tables.begin(); it != common_tables.end(); ++it) { - row_drop_table_for_mysql( - (*it)->name.m_name, trx, true, FALSE); + row_drop_table_for_mysql((*it)->name.m_name, trx, + SQLCOM_DROP_DB); } } @@ -2105,8 +2106,8 @@ fts_create_index_tables_low( for (it = aux_idx_tables.begin(); it != aux_idx_tables.end(); ++it) { - row_drop_table_for_mysql( - (*it)->name.m_name, trx, true, FALSE); + row_drop_table_for_mysql((*it)->name.m_name, trx, + SQLCOM_DROP_DB); } } @@ -6712,7 +6713,8 @@ fts_drop_obsolete_aux_table_from_vector( trx_start_for_ddl(trx_drop, TRX_DICT_OP_TABLE); err = row_drop_table_for_mysql( - aux_drop_table->name, trx_drop, false, true); + aux_drop_table->name, trx_drop, + SQLCOM_DROP_TABLE, true); trx_drop->dict_operation_lock_mode = 0; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index b363b4ff52e..5d79c22edcf 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -12647,7 +12647,8 @@ create_table_info_t::create_table() trx_rollback_to_savepoint(m_trx, NULL); m_trx->error_state = DB_SUCCESS; - row_drop_table_for_mysql(m_table_name, m_trx, true, FALSE); + row_drop_table_for_mysql(m_table_name, m_trx, + SQLCOM_DROP_DB); m_trx->error_state = DB_SUCCESS; DBUG_RETURN(error); @@ -12843,24 +12844,29 @@ create_table_info_t::allocate_trx() @param[in] name Table name, format: "db/table_name". @param[in] form Table format; columns and index information. @param[in] create_info Create info (including create statement string). +@param[in] file_per_table whether to create .ibd file +@param[in,out] trx dictionary transaction, or NULL to create new @return 0 if success else error number. */ -int +inline int ha_innobase::create( const char* name, TABLE* form, - HA_CREATE_INFO* create_info) + HA_CREATE_INFO* create_info, + bool file_per_table, + trx_t* trx) { int error; char norm_name[FN_REFLEN]; /* {database}/{tablename} */ char remote_path[FN_REFLEN]; /* Absolute path of table */ - trx_t* trx; + DBUG_ENTER("ha_innobase::create"); create_table_info_t info(ha_thd(), form, create_info, norm_name, - remote_path); + remote_path, + file_per_table, trx); /* Initialize the object. */ if ((error = info.initialize())) { @@ -12872,9 +12878,11 @@ ha_innobase::create( DBUG_RETURN(error); } - info.allocate_trx(); - - trx = info.trx(); + bool own_trx = !trx; + if (own_trx) { + info.allocate_trx(); + trx = info.trx(); + } /* Latch the InnoDB data dictionary exclusively so that no deadlocks or lock waits can happen in it during a table create operation. @@ -12882,10 +12890,16 @@ ha_innobase::create( row_mysql_lock_data_dictionary(trx); if ((error = info.create_table())) { - goto cleanup; + if (own_trx) { + trx_rollback_for_mysql(trx); + } + row_mysql_unlock_data_dictionary(trx); + goto func_exit; } - innobase_commit_low(trx); + if (own_trx) { + innobase_commit_low(trx); + } ut_ad(!srv_read_only_mode); row_mysql_unlock_data_dictionary(trx); @@ -12900,17 +12914,26 @@ ha_innobase::create( utility threads: */ srv_active_wake_master_thread(); - - trx_free_for_mysql(trx); +func_exit: + if (own_trx) { + trx_free_for_mysql(trx); + } DBUG_RETURN(error); +} -cleanup: - trx_rollback_for_mysql(trx); - row_mysql_unlock_data_dictionary(trx); - trx_free_for_mysql(trx); - - DBUG_RETURN(error); +/** Create a new table to an InnoDB database. +@param[in] name Table name, format: "db/table_name". +@param[in] form Table format; columns and index information. +@param[in] create_info Create info (including create statement string). +@return 0 if success else error number. */ +int +ha_innobase::create( + const char* name, + TABLE* form, + HA_CREATE_INFO* create_info) +{ + return create(name, form, create_info, srv_file_per_table); } /*****************************************************************//** @@ -13033,72 +13056,16 @@ ha_innobase::discard_or_import_tablespace( DBUG_RETURN(convert_error_code_to_mysql(err, dict_table->flags, NULL)); } -/*****************************************************************//** -Deletes all rows of an InnoDB table. -@return error number */ - -int -ha_innobase::truncate() -/*===================*/ -{ - DBUG_ENTER("ha_innobase::truncate"); - - if (high_level_read_only) { - DBUG_RETURN(HA_ERR_TABLE_READONLY); - } - - /* Get the transaction associated with the current thd, or create one - if not yet created, and update m_prebuilt->trx */ - - update_thd(ha_thd()); - - if (!trx_is_started(m_prebuilt->trx)) { - ++m_prebuilt->trx->will_lock; - } - - dberr_t err; - - /* Truncate the table in InnoDB */ - err = row_truncate_table_for_mysql(m_prebuilt->table, m_prebuilt->trx); - - int error; - - switch (err) { - case DB_TABLESPACE_DELETED: - case DB_TABLESPACE_NOT_FOUND: - ib_senderrf( - m_prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR, - (err == DB_TABLESPACE_DELETED ? - ER_TABLESPACE_DISCARDED : ER_TABLESPACE_MISSING), - table->s->table_name.str); - table->status = STATUS_NOT_FOUND; - error = HA_ERR_TABLESPACE_MISSING; - break; - - default: - error = convert_error_code_to_mysql( - err, m_prebuilt->table->flags, - m_prebuilt->trx->mysql_thd); - - table->status = STATUS_NOT_FOUND; - break; - } - - DBUG_RETURN(error); -} - -/*****************************************************************//** +/** Drops a table from an InnoDB database. Before calling this function, MySQL calls innobase_commit to commit the transaction of the current user. Then the current user cannot have locks set on the table. Drop table operation inside InnoDB will remove all locks any user has on the table inside InnoDB. +@param[in] name table name +@param[in] sqlcom SQLCOM_DROP_DB, SQLCOM_TRUNCATE, ... @return error number */ - -int -ha_innobase::delete_table( -/*======================*/ - const char* name) /*!< in: table name */ +inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom) { dberr_t err; THD* thd = ha_thd(); @@ -13162,9 +13129,7 @@ ha_innobase::delete_table( /* Drop the table in InnoDB */ - err = row_drop_table_for_mysql( - norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB, - false); + err = row_drop_table_for_mysql(norm_name, trx, sqlcom); if (err == DB_TABLE_NOT_FOUND && innobase_get_lower_case_table_names() == 1) { @@ -13188,9 +13153,7 @@ ha_innobase::delete_table( par_case_name, name, FALSE); #endif err = row_drop_table_for_mysql( - par_case_name, trx, - thd_sql_command(thd) == SQLCOM_DROP_DB, - FALSE); + par_case_name, trx, sqlcom); } } @@ -13253,9 +13216,7 @@ ha_innobase::delete_table( par_case_name, name, FALSE); #endif /* _WIN32 */ err = row_drop_table_for_mysql( - par_case_name, trx, - thd_sql_command(thd) == SQLCOM_DROP_DB, - true); + par_case_name, trx, sqlcom, true); } } @@ -13273,6 +13234,25 @@ ha_innobase::delete_table( DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL)); } +/** Drop an InnoDB table. +@param[in] name table name +@return error number */ +int ha_innobase::delete_table(const char* name) +{ + enum_sql_command sqlcom = enum_sql_command(thd_sql_command(ha_thd())); + + if (sqlcom == SQLCOM_TRUNCATE + && thd_killed(ha_thd()) + && (m_prebuilt == NULL + || dict_table_is_temporary(m_prebuilt->table))) { + sqlcom = SQLCOM_DROP_TABLE; + } + + /* SQLCOM_TRUNCATE will be passed via ha_innobase::truncate() only. */ + DBUG_ASSERT(sqlcom != SQLCOM_TRUNCATE); + return delete_table(name, sqlcom); +} + /** Remove all tables in the named database inside InnoDB. @param[in] hton handlerton from InnoDB @param[in] path Database path; Inside InnoDB the name of the last @@ -13347,7 +13327,7 @@ innobase_drop_database( /*********************************************************************//** Renames an InnoDB table. @return DB_SUCCESS or error code */ -inline MY_ATTRIBUTE((warn_unused_result)) +inline dberr_t innobase_rename_table( /*==================*/ @@ -13360,7 +13340,8 @@ innobase_rename_table( char norm_from[FN_REFLEN]; DBUG_ENTER("innobase_rename_table"); - DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX); + DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX + || trx_get_dict_operation(trx) == TRX_DICT_OP_TABLE); ut_ad(!srv_read_only_mode); @@ -13471,6 +13452,89 @@ innobase_rename_table( DBUG_RETURN(error); } +/** TRUNCATE TABLE +@return error code +@retval 0 on success */ +int ha_innobase::truncate() +{ + DBUG_ENTER("ha_innobase::truncate"); + + if (high_level_read_only) { + DBUG_RETURN(HA_ERR_TABLE_READONLY); + } + + update_thd(); + + HA_CREATE_INFO info; + mem_heap_t* heap = mem_heap_create(1000); + dict_table_t* ib_table = m_prebuilt->table; + const time_t update_time = ib_table->update_time; + const ulint stored_lock = m_prebuilt->stored_select_lock_type; + memset(&info, 0, sizeof info); + update_create_info_from_table(&info, table); + + if (dict_table_is_temporary(ib_table)) { + info.options|= HA_LEX_CREATE_TMP_TABLE; + } else { + dict_get_and_save_data_dir_path(ib_table, false); + } + + char* data_file_name = ib_table->data_dir_path; + + if (data_file_name) { + info.data_file_name = data_file_name + = mem_heap_strdup(heap, data_file_name); + } + + const char* temp_name = dict_mem_create_temporary_tablename( + heap, ib_table->name.m_name, ib_table->id); + const char* name = mem_heap_strdup(heap, ib_table->name.m_name); + trx_t* trx = innobase_trx_allocate(m_user_thd); + + ++trx->will_lock; + trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); + int err = convert_error_code_to_mysql( + innobase_rename_table(trx, ib_table->name.m_name, temp_name), + ib_table->flags, m_user_thd); + if (!err) { + err = create(name, table, &info, + dict_table_is_file_per_table(ib_table), trx); + } + + if (err) { + /* Before MDEV-14717, rollback of RENAME TABLE fails + to undo the rename in the file system, so we do it + manually here. In case the server is killed before the + TRUNCATE operation is committed, after recovery in + MariaDB 10.2, the data file could end up "missing" + (remain called temp_name). */ + innobase_rename_table(trx, temp_name, name); + trx_rollback_to_savepoint(trx, NULL); + } + + innobase_commit_low(trx); + trx_free_for_mysql(trx); + + if (!err) { + /* Reopen the newly created table, and drop the + original table that was renamed to temp_name. + + Note: In MariaDB 10.2 (before MDEV-14585), if the + server is killed and restarted before the original + table is dropped, the table will remain orphaned. */ + close(); + err = open(name, 0, 0); + if (!err) { + m_prebuilt->stored_select_lock_type = stored_lock; + m_prebuilt->table->update_time = update_time; + delete_table(temp_name, SQLCOM_TRUNCATE); + } + } + + mem_heap_free(heap); + DBUG_RETURN(err); +} + /*********************************************************************//** Renames an InnoDB table. @return 0 or error code */ diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index ab1d3bbeac3..9ba7189a3bc 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -26,6 +26,9 @@ extern const char innobase_index_reserve_name[]; /** Prebuilt structures in an InnoDB table handle used within MySQL */ struct row_prebuilt_t; +/** InnoDB transaction */ +struct trx_t; + /** Engine specific table options are defined using this struct */ struct ha_table_option_struct { @@ -196,6 +199,13 @@ public: void update_create_info(HA_CREATE_INFO* create_info); + inline int create( + const char* name, + TABLE* form, + HA_CREATE_INFO* create_info, + bool file_per_table, + trx_t* trx = NULL); + int create( const char* name, TABLE* form, @@ -204,6 +214,8 @@ public: const char* check_table_options(THD *thd, TABLE* table, HA_CREATE_INFO* create_info, const bool use_tablespace, const ulint file_format); + inline int delete_table(const char* name, enum_sql_command sqlcom); + int truncate(); int delete_table(const char *name); @@ -641,13 +653,16 @@ public: TABLE* form, HA_CREATE_INFO* create_info, char* table_name, - char* remote_path) + char* remote_path, + bool file_per_table, + trx_t* trx = NULL) :m_thd(thd), + m_trx(trx), m_form(form), m_create_info(create_info), m_table_name(table_name), m_remote_path(remote_path), - m_innodb_file_per_table(srv_file_per_table) + m_innodb_file_per_table(file_per_table) {} /** Initialize the object. */ diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index d4a5a43ca37..8565cad96ec 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -5579,7 +5579,8 @@ ha_innobase::prepare_inplace_alter_table( altered_table, ha_alter_info->create_info, NULL, - NULL); + NULL, + srv_file_per_table); info.set_tablespace_type(indexed_table->space != TRX_SYS_SPACE); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index fe0b4556fa2..ca1b10932db 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -4795,7 +4795,7 @@ reset_bit: /*********************************************************************//** Deletes all entries in the insert buffer for a given space id. This is used -in DISCARD TABLESPACE, IMPORT TABLESPACE and TRUNCATE TABLESPACE. +in DISCARD TABLESPACE, IMPORT TABLESPACE, and 5.7 TRUNCATE TABLE recovery. NOTE: this does not update the page free bitmaps in the space. The space will become CORRUPT when you call this function! */ void diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 4d284aa2fba..10dcdb27eb0 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -64,8 +64,10 @@ bool buf_LRU_drop_page_hash_for_tablespace(dict_table_t* table) /** Empty the flush list for all pages belonging to a tablespace. @param[in] id tablespace identifier @param[in,out] observer flush observer, - or NULL if nothing is to be written */ -void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer); + or NULL if nothing is to be written +@param[in] first first page to be flushed or evicted */ +void buf_LRU_flush_or_remove_pages(ulint id, FlushObserver* observer, + ulint first = 0); #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /********************************************************************//** diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h index 86a4bcf23a3..12c78862261 100644 --- a/storage/innobase/include/dict0crea.h +++ b/storage/innobase/include/dict0crea.h @@ -151,14 +151,6 @@ dict_create_index_tree_in_mem( dict_index_t* index, /*!< in/out: index */ const trx_t* trx); /*!< in: InnoDB transaction handle */ -/*******************************************************************//** -Truncates the index tree but don't update SYSTEM TABLES. -@return DB_SUCCESS or error */ -dberr_t -dict_truncate_index_tree_in_mem( -/*============================*/ - dict_index_t* index); /*!< in/out: index */ - /*******************************************************************//** Drops the index tree but don't update SYS_INDEXES table. */ void diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 8aa8a746ce1..b2ee24c969b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -101,10 +101,8 @@ struct fil_space_t { new write operations because we don't check this flag when doing flush batches. */ + /** whether undo tablespace truncation is in progress */ bool is_being_truncated; - /*!< this is set to true when we prepare to - truncate a single-table tablespace and its - .ibd file */ #ifdef UNIV_DEBUG ulint redo_skipped_count; /*!< reference count for operations who want @@ -188,12 +186,8 @@ struct fil_space_t { ulint magic_n;/*!< FIL_SPACE_MAGIC_N */ - /** @return whether the tablespace is about to be dropped or - truncated */ - bool is_stopping() const - { - return stop_new_ops || is_being_truncated; - } + /** @return whether the tablespace is about to be dropped */ + bool is_stopping() const { return stop_new_ops; } /** @return whether doublewrite buffering is needed */ bool use_doublewrite() const @@ -923,7 +917,8 @@ fil_op_replay_rename( not (necessarily) protected by meta-data locks. (Rollback would generally be protected, but rollback of FOREIGN KEY CASCADE/SET NULL is not protected by meta-data locks -but only by InnoDB table locks, which may be broken by TRUNCATE TABLE.) +but only by InnoDB table locks, which may be broken by +lock_remove_all_on_table().) @param[in] table persistent table checked @return whether the table is accessible */ bool @@ -941,36 +936,15 @@ fil_delete_tablespace( #endif /* BTR_CUR_HASH_ADAPT */ ); -/** Truncate the tablespace to needed size. -@param[in] space_id id of tablespace to truncate -@param[in] size_in_pages truncate size. -@return true if truncate was successful. */ -bool -fil_truncate_tablespace( - ulint space_id, - ulint size_in_pages); +/** Prepare to truncate an undo tablespace. +@param[in] space_id undo tablespace id +@return the tablespace +@retval NULL if the tablespace does not exist */ +fil_space_t* fil_truncate_prepare(ulint space_id); -/*******************************************************************//** -Prepare for truncating a single-table tablespace. The tablespace -must be cached in the memory cache. -1) Check pending operations on a tablespace; -2) Remove all insert buffer entries for the tablespace; -@return DB_SUCCESS or error */ -dberr_t -fil_prepare_for_truncate( -/*=====================*/ - ulint id); /*!< in: space id */ - -/** Reinitialize the original tablespace header with the same space id -for single tablespace -@param[in] table table belongs to the tablespace -@param[in] size size in blocks -@param[in] trx Transaction covering truncate */ -void -fil_reinit_space_header_for_table( - dict_table_t* table, - ulint size, - trx_t* trx); +/** Write log about an undo tablespace truncate operation. */ +void fil_truncate_log(fil_space_t* space, ulint size, mtr_t* mtr) + MY_ATTRIBUTE((nonnull)); /*******************************************************************//** Closes a single-table tablespace. The tablespace must be cached in the diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index f7d507813e3..45f69cad9a5 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -510,7 +510,7 @@ lock_trx_release_locks( /*===================*/ trx_t* trx); /*!< in/out: transaction */ /*********************************************************************//** -Removes locks on a table to be dropped or truncated. +Removes locks on a table to be dropped or discarded. If remove_also_table_sx_locks is TRUE then table-level S and X locks are also removed in addition to other table-level and record-level locks. No lock, that is going to be removed, is allowed to be a wait lock. */ @@ -518,7 +518,7 @@ void lock_remove_all_on_table( /*=====================*/ dict_table_t* table, /*!< in: table to be dropped - or truncated */ + or discarded */ ibool remove_also_table_sx_locks);/*!< in: also removes table S and X locks */ diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 91ca389df83..cd3f415a8d7 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -490,10 +490,12 @@ to this checkpoint, or 0 if the information has not been written */ This used to be called LOG_GROUP_ID and always written as 0, because InnoDB never supported more than one copy of the redo log. */ #define LOG_HEADER_FORMAT 0 -/** 4 unused (zero-initialized) bytes. In format version 0, the +/** Redo log subformat (originally 0). In format version 0, the LOG_FILE_START_LSN started here, 4 bytes earlier than LOG_HEADER_START_LSN, -which the LOG_FILE_START_LSN was renamed to. */ -#define LOG_HEADER_PAD1 4 +which the LOG_FILE_START_LSN was renamed to. +Subformat 1 is for the fully redo-logged TRUNCATE +(no MLOG_TRUNCATE records or extra log checkpoints or log files) */ +#define LOG_HEADER_SUBFORMAT 4 /** LSN of the start of data in this log file (with format version 1; in format version 0, it was called LOG_FILE_START_LSN and at offset 4). */ #define LOG_HEADER_START_LSN 8 diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index b8eb74aa08f..d3c891c9cba 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -280,6 +280,15 @@ struct recv_sys_t{ ulint n_addrs;/*!< number of not processed hashed file addresses in the hash table */ + /** Undo tablespaces for which truncate has been logged + (indexed by id - srv_undo_space_id_start) */ + struct trunc { + /** log sequence number of MLOG_FILE_CREATE2, or 0 if none */ + lsn_t lsn; + /** truncated size of the tablespace, or 0 if not truncated */ + unsigned pages; + } truncated_undo_spaces[127]; + recv_dblwr_t dblwr; /** Lastly added LSN to the hash table of log records. */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 200af211d4d..c19079e1f9e 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1263,17 +1263,18 @@ bool os_file_set_eof( FILE* file); /*!< in: file to be truncated */ -/** Truncates a file to a specified size in bytes. Do nothing if the size -preserved is smaller or equal than current size of file. +/** Truncate a file to a specified size in bytes. @param[in] pathname file path @param[in] file file to be truncated @param[in] size size preserved in bytes +@param[in] allow_shrink whether to allow the file to become smaller @return true if success */ bool os_file_truncate( const char* pathname, os_file_t file, - os_offset_t size); + os_offset_t size, + bool allow_shrink = false); /** NOTE! Use the corresponding macro os_file_flush(), not directly this function! diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 8a573a23652..417aee02132 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -29,6 +29,8 @@ Created 9/17/2000 Heikki Tuuri #define row0mysql_h #include "ha_prototypes.h" +#include "sql_list.h" +#include "sql_cmd.h" #include "data0data.h" #include "que0types.h" @@ -434,32 +436,28 @@ row_mysql_lock_table( const char* op_info) /*!< in: string for trx->op_info */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** -Truncates a table for MySQL. -@return error code or DB_SUCCESS */ -dberr_t -row_truncate_table_for_mysql( -/*=========================*/ - dict_table_t* table, /*!< in: table handle */ - trx_t* trx) /*!< in: transaction handle */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** -Drops a table for MySQL. If the data dictionary was not already locked -by the transaction, the transaction will be committed. Otherwise, the -data dictionary will remain locked. -@return error code or DB_SUCCESS */ +/** Drop a table. +If the data dictionary was not already locked by the transaction, +the transaction will be committed. Otherwise, the data dictionary +will remain locked. +@param[in] name Table name +@param[in,out] trx Transaction handle +@param[in] sqlcom type of SQL operation +@param[in] create_failed true=create table failed + because e.g. foreign key column +@param[in] nonatomic Whether it is permitted to release + and reacquire dict_operation_lock +@return error code */ dberr_t row_drop_table_for_mysql( -/*=====================*/ - const char* name, /*!< in: table name */ - trx_t* trx, /*!< in: dictionary transaction handle */ - bool drop_db,/*!< in: true=dropping whole database */ - ibool create_failed,/*! undo_spaces_t; typedef std::vector rseg_for_trunc_t; - /** Magic Number to indicate truncate action is complete. */ - const ib_uint32_t s_magic = 76845412; - - /** Truncate Log file Prefix. */ - const char* const s_log_prefix = "undo_"; - - /** Truncate Log file Extension. */ - const char* const s_log_ext = "trunc.log"; - - /** Populate log file name based on space_id - @param[in] space_id id of the undo tablespace. - @return DB_SUCCESS or error code */ - dberr_t populate_log_file_name( - ulint space_id, - char*& log_file_name); - - /** Create the truncate log file. - @param[in] space_id id of the undo tablespace to truncate. - @return DB_SUCCESS or error code. */ - dberr_t init(ulint space_id); - /** Mark completion of undo truncate action by writing magic number to the log file and then removing it from the disk. If we are going to remove it from disk then why write magic number ? @@ -439,23 +418,6 @@ namespace undo { return(m_purge_rseg_truncate_frequency); } - /* Start writing log information to a special file. - On successfull completion, file is removed. - On crash, file is used to complete the truncate action. - @param space_id space id of undo tablespace - @return DB_SUCCESS or error code. */ - dberr_t start_logging(ulint space_id) - { - return(init(space_id)); - } - - /* Mark completion of logging./ - @param space_id space id of undo tablespace */ - void done_logging(ulint space_id) - { - return(done(space_id)); - } - private: /** UNDO tablespace is mark for truncate. */ ulint m_undo_for_trunc; diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index f744364d966..f738af4b454 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2018, MariaDB Corporation. 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 @@ -316,18 +316,6 @@ trx_undo_free_prepared( trx_t* trx) /*!< in/out: PREPARED transaction */ ATTRIBUTE_COLD __attribute__((nonnull)); -/* Forward declaration. */ -namespace undo { - class Truncate; -}; - -/** Truncate UNDO tablespace, reinitialize header and rseg. -@param[in] undo_trunc UNDO tablespace handler -@return true if success else false. */ -bool -trx_undo_truncate_tablespace( - undo::Truncate* undo_trunc); - /***********************************************************//** Parses the redo log entry of an undo log page initialization. @return end of log record or NULL */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 02fcbc74757..3169313d874 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4635,7 +4635,7 @@ lock_remove_recovered_trx_record_locks( } /*********************************************************************//** -Removes locks on a table to be dropped or truncated. +Removes locks on a table to be dropped or discarded. If remove_also_table_sx_locks is TRUE then table-level S and X locks are also removed in addition to other table-level and record-level locks. No lock, that is going to be removed, is allowed to be a wait lock. */ @@ -4643,7 +4643,7 @@ void lock_remove_all_on_table( /*=====================*/ dict_table_t* table, /*!< in: table to be dropped - or truncated */ + or discarded */ ibool remove_also_table_sx_locks)/*!< in: also removes table S and X locks */ { @@ -5226,9 +5226,8 @@ lock_trx_print_locks( } /* It is a single table tablespace - and the .ibd file is missing - (TRUNCATE TABLE probably stole the - locks): just print the lock without + and the .ibd file is missing: + just print the lock without attempting to load the page in the buffer pool. */ diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index abd18a6f559..209decae021 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -880,6 +880,7 @@ log_group_file_header_flush( memset(buf, 0, OS_FILE_LOG_BLOCK_SIZE); mach_write_to_4(buf + LOG_HEADER_FORMAT, group->format); + mach_write_to_4(buf + LOG_HEADER_SUBFORMAT, 1); mach_write_to_8(buf + LOG_HEADER_START_LSN, start_lsn); strcpy(reinterpret_cast(buf) + LOG_HEADER_CREATOR, LOG_HEADER_CREATOR_CURRENT); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 5c91342240e..a1b031f5b1e 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -131,8 +131,7 @@ bool recv_writer_thread_active; /** Return string name of the redo log record type. @param[in] type record log record enum @return string name of record log record */ -const char* -get_mlog_string(mlog_id_t type); +static const char* get_mlog_string(mlog_id_t type); #endif /* !DBUG_OFF */ /** Tablespace item during recovery */ @@ -219,6 +218,75 @@ void (*log_file_op)(ulint space_id, const byte* flags, const byte* name, ulint len, const byte* new_name, ulint new_len); +/** Process a MLOG_CREATE2 record that indicates that a tablespace +is being shrunk in size. +@param[in] space_id tablespace identifier +@param[in] pages trimmed size of the file, in pages +@param[in] lsn log sequence number of the operation */ +static void recv_addr_trim(ulint space_id, unsigned pages, lsn_t lsn) +{ + DBUG_ENTER("recv_addr_trim"); + DBUG_LOG("ib_log", + "discarding log beyond end of tablespace " + << page_id_t(space_id, pages) << " before LSN " << lsn); + ut_ad(mutex_own(&recv_sys->mutex)); + for (ulint i = recv_sys->addr_hash->n_cells; i--; ) { + hash_cell_t* const cell = hash_get_nth_cell( + recv_sys->addr_hash, i); + for (recv_addr_t* addr = static_cast(cell->node), + *prev = NULL, *next; + addr; + prev = addr, addr = next) { + next = static_cast(addr->addr_hash); + + if (addr->space != space_id || addr->page_no < pages) { + continue; + } + + for (recv_t* recv = UT_LIST_GET_FIRST(addr->rec_list); + recv; ) { + recv_t* n = UT_LIST_GET_NEXT(rec_list, recv); + if (recv->start_lsn < lsn) { + DBUG_PRINT("ib_log", + ("Discarding %s for" + " page %u:%u at " LSN_PF, + get_mlog_string( + recv->type), + addr->space, addr->page_no, + recv->start_lsn)); + UT_LIST_REMOVE(addr->rec_list, recv); + } + recv = n; + } + + if (UT_LIST_GET_LEN(addr->rec_list)) { + DBUG_PRINT("ib_log", + ("preserving " ULINTPF + " records for page %u:%u", + UT_LIST_GET_LEN(addr->rec_list), + addr->space, addr->page_no)); + } else { + ut_ad(recv_sys->n_addrs); + --recv_sys->n_addrs; + if (addr == cell->node) { + cell->node = next; + } else { + prev->addr_hash = next; + } + } + } + } + if (fil_space_t* space = fil_space_get(space_id)) { + ut_ad(UT_LIST_GET_LEN(space->chain) == 1); + fil_node_t* file = UT_LIST_GET_FIRST(space->chain); + ut_ad(file->is_open()); + os_file_truncate(file->name, file->handle, + os_offset_t(pages) << srv_page_size_shift, + true); + } + DBUG_VOID_RETURN; +} + /** Process a file name from a MLOG_FILE_* record. @param[in,out] name file name @param[in] len length of the file name @@ -391,9 +459,8 @@ fil_name_parse( user-created tablespaces. The name must be long enough and end in .ibd. */ bool corrupt = is_predefined_tablespace(space_id) - || first_page_no != 0 // TODO: multi-file user tablespaces || len < sizeof "/a.ibd\0" - || memcmp(ptr + len - 5, DOT_IBD, 5) != 0 + || (!first_page_no != !memcmp(ptr + len - 5, DOT_IBD, 5)) || memchr(ptr, OS_PATH_SEPARATOR, len) == NULL; byte* end_ptr = ptr + len; @@ -422,7 +489,18 @@ fil_name_parse( reinterpret_cast(ptr), len, space_id, true); /* fall through */ case MLOG_FILE_CREATE2: - if (log_file_op) { + if (first_page_no) { + ut_ad(first_page_no + == SRV_UNDO_TABLESPACE_SIZE_IN_PAGES); + ut_a(srv_is_undo_tablespace(space_id)); + compile_time_assert( + UT_ARR_SIZE(recv_sys->truncated_undo_spaces) + == TRX_SYS_MAX_UNDO_SPACES); + recv_sys_t::trunc& t = recv_sys->truncated_undo_spaces[ + space_id - srv_undo_space_id_start]; + t.lsn = recv_sys->recovered_lsn; + t.pages = uint32_t(first_page_no); + } else if (log_file_op) { log_file_op(space_id, type == MLOG_FILE_CREATE2 ? ptr - 4 : NULL, ptr, len, NULL, 0); @@ -2118,6 +2196,14 @@ recv_apply_hashed_log_recs(bool last_batch) recv_sys->apply_log_recs = TRUE; recv_sys->apply_batch_on = TRUE; + for (ulint id = srv_undo_tablespaces_open; id--; ) { + recv_sys_t::trunc& t = recv_sys->truncated_undo_spaces[id]; + if (t.lsn) { + recv_addr_trim(id + srv_undo_space_id_start, t.pages, + t.lsn); + } + } + for (ulint i = 0; i < hash_get_n_cells(recv_sys->addr_hash); i++) { for (recv_addr_t* recv_addr = static_cast( HASH_GET_FIRST(recv_sys->addr_hash, i)); @@ -3753,8 +3839,7 @@ recv_dblwr_t::find_page(ulint space_id, ulint page_no) /** Return string name of the redo log record type. @param[in] type record log record enum @return string name of record log record */ -const char* -get_mlog_string(mlog_id_t type) +static const char* get_mlog_string(mlog_id_t type) { switch (type) { case MLOG_SINGLE_REC_FLAG: diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 05131eb69b0..4d71eaf552b 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -5456,25 +5456,27 @@ fallback: return(current_size >= size && os_file_flush(file)); } -/** Truncates a file to a specified size in bytes. -Do nothing if the size to preserve is greater or equal to the current -size of the file. +/** Truncate a file to a specified size in bytes. @param[in] pathname file path @param[in] file file to be truncated -@param[in] size size to preserve in bytes +@param[in] size size preserved in bytes +@param[in] allow_shrink whether to allow the file to become smaller @return true if success */ bool os_file_truncate( const char* pathname, os_file_t file, - os_offset_t size) + os_offset_t size, + bool allow_shrink) { - /* Do nothing if the size preserved is larger than or equal to the - current size of file */ - os_offset_t size_bytes = os_file_get_size(file); + if (!allow_shrink) { + /* Do nothing if the size preserved is larger than or + equal to the current size of file */ + os_offset_t size_bytes = os_file_get_size(file); - if (size >= size_bytes) { - return(true); + if (size >= size_bytes) { + return(true); + } } #ifdef _WIN32 diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 66948b83cda..57796939be1 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1629,8 +1629,7 @@ row_ins_check_foreign_constraint( if (check_table == NULL || !check_table->is_readable() - || check_index == NULL - || fil_space_get(check_table->space)->is_being_truncated) { + || check_index == NULL) { if (!srv_read_only_mode && check_ref) { FILE* ef = dict_foreign_err_file; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 348611217cb..427bf345930 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -4475,7 +4475,7 @@ row_merge_drop_table( ut_a(table->get_ref_count() == 0); return(row_drop_table_for_mysql(table->name.m_name, - trx, false, false, false)); + trx, SQLCOM_DROP_TABLE, false, false)); } /** Write an MLOG_INDEX_LOAD record to indicate in the redo-log diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index e1fe6e15067..97c04546ee7 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2499,7 +2499,8 @@ error_handling: trx_rollback_to_savepoint(trx, NULL); } - row_drop_table_for_mysql(table_name, trx, FALSE, true); + row_drop_table_for_mysql(table_name, trx, SQLCOM_DROP_TABLE, + true); if (trx_is_started(trx)) { @@ -2591,7 +2592,7 @@ row_table_add_foreign_constraints( trx_rollback_to_savepoint(trx, NULL); } - row_drop_table_for_mysql(name, trx, FALSE, true); + row_drop_table_for_mysql(name, trx, SQLCOM_DROP_TABLE, true); if (trx_is_started(trx)) { @@ -2631,7 +2632,7 @@ row_drop_table_for_mysql_in_background( /* Try to drop the table in InnoDB */ - error = row_drop_table_for_mysql(name, trx, FALSE, FALSE); + error = row_drop_table_for_mysql(name, trx, SQLCOM_TRUNCATE); /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -2777,6 +2778,7 @@ func_exit: @param[in,out] trx transaction @param[out] new_id new table id @return error code or DB_SUCCESS */ +static dberr_t row_mysql_table_id_reassign( dict_table_t* table, @@ -3259,7 +3261,7 @@ row_drop_table_from_cache( trx_t* trx) { dberr_t err = DB_SUCCESS; - bool is_temp = dict_table_is_temporary(table); + ut_ad(!dict_table_is_temporary(table)); /* Remove the pointer to this table object from the list of modified tables by the transaction because the object @@ -3268,9 +3270,7 @@ row_drop_table_from_cache( dict_table_remove_from_cache(table); - if (!is_temp - && dict_load_table(tablename, true, - DICT_ERR_IGNORE_NONE) != NULL) { + if (dict_load_table(tablename, true, DICT_ERR_IGNORE_NONE)) { ib::error() << "Not able to remove table " << ut_get_name(trx, tablename) << " from the dictionary cache!"; @@ -3319,25 +3319,25 @@ row_drop_single_table_tablespace( return(err); } -/** Drop a table for MySQL. +/** Drop a table. If the data dictionary was not already locked by the transaction, the transaction will be committed. Otherwise, the data dictionary will remain locked. @param[in] name Table name -@param[in] trx Transaction handle -@param[in] drop_db true=dropping whole database -@param[in] create_failed TRUE=create table failed +@param[in,out] trx Transaction handle +@param[in] sqlcom type of SQL operation +@param[in] create_failed true=create table failed because e.g. foreign key column @param[in] nonatomic Whether it is permitted to release and reacquire dict_operation_lock @return error code or DB_SUCCESS */ dberr_t row_drop_table_for_mysql( - const char* name, - trx_t* trx, - bool drop_db, - ibool create_failed, - bool nonatomic) + const char* name, + trx_t* trx, + enum_sql_command sqlcom, + bool create_failed, + bool nonatomic) { dberr_t err; dict_foreign_t* foreign; @@ -3500,7 +3500,7 @@ row_drop_table_for_mysql( foreign = *it; - const bool ref_ok = drop_db + const bool ref_ok = sqlcom == SQLCOM_DROP_DB && dict_tables_have_same_db( name, foreign->foreign_table_name_lookup); @@ -3537,7 +3537,6 @@ row_drop_table_for_mysql( } } - DBUG_EXECUTE_IF("row_drop_table_add_to_background", row_add_table_to_background_drop_list(table->id); err = DB_SUCCESS; @@ -3587,11 +3586,14 @@ row_drop_table_for_mysql( ut_a(table->n_rec_locks == 0); } else if (table->get_ref_count() > 0 || table->n_rec_locks > 0) { if (row_add_table_to_background_drop_list(table->id)) { - ib::info() << "MySQL is trying to drop table " - << table->name - << " though there are still open handles to" - " it. Adding the table to the background drop" - " queue."; + if (!strstr(table->name.m_name, + "/" TEMP_FILE_PREFIX_INNODB)) { + ib::info() << "MySQL is trying to drop table " + << table->name + << " though there are still " + "open handles to it. Adding the table " + "to the background drop queue."; + } /* We return DB_SUCCESS to MySQL though the drop will happen lazily later */ @@ -3626,9 +3628,9 @@ row_drop_table_for_mysql( /* If the transaction was previously flagged as TRX_DICT_OP_INDEX, we should be dropping auxiliary tables for full-text indexes or temp tables. */ - ut_ad(strstr(table->name.m_name, "/FTS_") != NULL - || strstr(table->name.m_name, TEMP_FILE_PREFIX_INNODB) - != NULL); + ut_ad(strstr(table->name.m_name, "/FTS_") + || strstr(table->name.m_name, + "/" TEMP_FILE_PREFIX_INNODB)); } /* Mark all indexes unavailable in the data dictionary cache @@ -3670,12 +3672,11 @@ row_drop_table_for_mysql( pars_info_add_str_literal(info, "table_name", name); - err = que_eval_sql( + err = (sqlcom == SQLCOM_TRUNCATE) ? DB_SUCCESS : que_eval_sql( info, - "PROCEDURE DROP_TABLE_PROC () IS\n" + "PROCEDURE DROP_FOREIGN_PROC () IS\n" "sys_foreign_id CHAR;\n" "table_id CHAR;\n" - "index_id CHAR;\n" "foreign_id CHAR;\n" "space_id INT;\n" "found INT;\n" @@ -3687,11 +3688,6 @@ row_drop_table_for_mysql( " = TO_BINARY(:table_name)\n" "LOCK IN SHARE MODE;\n" - "DECLARE CURSOR cur_idx IS\n" - "SELECT ID FROM SYS_INDEXES\n" - "WHERE TABLE_ID = table_id\n" - "LOCK IN SHARE MODE;\n" - "BEGIN\n" "SELECT ID INTO table_id\n" @@ -3740,21 +3736,35 @@ row_drop_table_for_mysql( "END LOOP;\n" "CLOSE cur_fk;\n" - "found := 1;\n" - "OPEN cur_idx;\n" - "WHILE found = 1 LOOP\n" - " FETCH cur_idx INTO index_id;\n" - " IF (SQL % NOTFOUND) THEN\n" - " found := 0;\n" - " ELSE\n" - " DELETE FROM SYS_FIELDS\n" - " WHERE INDEX_ID = index_id;\n" - " DELETE FROM SYS_INDEXES\n" - " WHERE ID = index_id\n" - " AND TABLE_ID = table_id;\n" - " END IF;\n" - "END LOOP;\n" - "CLOSE cur_idx;\n" + "END;\n", + FALSE, trx); + + if (err == DB_SUCCESS) { + if (sqlcom != SQLCOM_TRUNCATE) { + info = pars_info_create(); + pars_info_add_str_literal(info, "table_name", + name); + } + + err = que_eval_sql( + info, + "PROCEDURE DROP_TABLE_PROC () IS\n" + "table_id CHAR;\n" + "space_id INT;\n" + "index_id CHAR;\n" + + "DECLARE CURSOR cur_idx IS\n" + "SELECT ID FROM SYS_INDEXES\n" + "WHERE TABLE_ID = table_id\n" + "FOR UPDATE;\n" + + "BEGIN\n" + "SELECT ID, SPACE INTO table_id,space_id\n" + "FROM SYS_TABLES\n" + "WHERE NAME = :table_name FOR UPDATE;\n" + "IF (SQL % NOTFOUND) THEN\n" + " RETURN;\n" + "END IF;\n" "DELETE FROM SYS_COLUMNS\n" "WHERE TABLE_ID = table_id;\n" @@ -3768,8 +3778,25 @@ row_drop_table_for_mysql( "DELETE FROM SYS_VIRTUAL\n" "WHERE TABLE_ID = table_id;\n" + + "OPEN cur_idx;\n" + "WHILE 1 = 1 LOOP\n" + " FETCH cur_idx INTO index_id;\n" + " IF (SQL % NOTFOUND) THEN\n" + " EXIT;\n" + " ELSE\n" + " DELETE FROM SYS_FIELDS\n" + " WHERE INDEX_ID = index_id;\n" + " DELETE FROM SYS_INDEXES\n" + " WHERE ID = index_id\n" + " AND TABLE_ID = table_id;\n" + " END IF;\n" + "END LOOP;\n" + "CLOSE cur_idx;\n" + "END;\n", FALSE, trx); + } } else { page_no = page_nos; for (dict_index_t* index = dict_table_get_first_index(table); @@ -3778,7 +3805,9 @@ row_drop_table_for_mysql( /* remove the index object associated. */ dict_drop_index_tree_in_mem(index, *page_no++); } - err = row_drop_table_from_cache(tablename, table, trx); + trx->mod_tables.erase(table); + dict_table_remove_from_cache(table); + err = DB_SUCCESS; goto funct_exit; } @@ -3907,6 +3936,13 @@ funct_exit: DBUG_RETURN(err); } +/** Drop a table after failed CREATE TABLE. */ +dberr_t row_drop_table_after_create_fail(const char* name, trx_t* trx) +{ + ib::warn() << "Dropping incompletely created " << name << " table."; + return row_drop_table_for_mysql(name, trx, SQLCOM_DROP_DB, true); +} + /*******************************************************************//** Drop all foreign keys in a database, see Bug#18942. Called at the end of row_drop_database_for_mysql(). @@ -4095,7 +4131,8 @@ loop: goto loop; } - err = row_drop_table_for_mysql(table_name, trx, TRUE, FALSE); + err = row_drop_table_for_mysql( + table_name, trx, SQLCOM_DROP_DB); trx_commit_for_mysql(trx); if (err != DB_SUCCESS) { diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index 79870ceaf5f..79bffe498dd 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -240,335 +240,6 @@ protected: const bool m_noredo; }; -/** -Creates a TRUNCATE log record with space id, table name, data directory path, -tablespace flags, table format, index ids, index types, number of index fields -and index field information of the table. */ -class TruncateLogger : public Callback { - -public: - /** - Constructor - - @param table Table to truncate - @param flags tablespace falgs */ - TruncateLogger( - dict_table_t* table, - ulint flags, - table_id_t new_table_id) - : - Callback(table->id, false), - m_table(table), - m_flags(flags), - m_truncate(table->id, new_table_id, table->data_dir_path), - m_log_file_name() - { - /* Do nothing */ - } - - /** - Initialize Truncate Logger by constructing Truncate Log File Name. - - @return DB_SUCCESS or error code. */ - dberr_t init() - { - /* Construct log file name. */ - ulint log_file_name_buf_sz = - strlen(srv_log_group_home_dir) + 22 + 22 + 1 /* NUL */ - + strlen(TruncateLogger::s_log_prefix) - + strlen(TruncateLogger::s_log_ext); - - m_log_file_name = UT_NEW_ARRAY_NOKEY(char, log_file_name_buf_sz); - if (m_log_file_name == NULL) { - return(DB_OUT_OF_MEMORY); - } - memset(m_log_file_name, 0, log_file_name_buf_sz); - - strcpy(m_log_file_name, srv_log_group_home_dir); - ulint log_file_name_len = strlen(m_log_file_name); - if (m_log_file_name[log_file_name_len - 1] - != OS_PATH_SEPARATOR) { - - m_log_file_name[log_file_name_len] - = OS_PATH_SEPARATOR; - log_file_name_len = strlen(m_log_file_name); - } - - snprintf(m_log_file_name + log_file_name_len, - log_file_name_buf_sz - log_file_name_len, - "%s%lu_%lu_%s", - TruncateLogger::s_log_prefix, - (ulong) m_table->space, - (ulong) m_table->id, - TruncateLogger::s_log_ext); - - return(DB_SUCCESS); - - } - - /** - Destructor */ - ~TruncateLogger() - { - if (m_log_file_name != NULL) { - bool exist; - os_file_delete_if_exists( - innodb_log_file_key, m_log_file_name, &exist); - UT_DELETE_ARRAY(m_log_file_name); - m_log_file_name = NULL; - } - } - - /** - @param mtr mini-transaction covering the read - @param pcur persistent cursor used for reading - @return DB_SUCCESS or error code */ - dberr_t operator()(mtr_t* mtr, btr_pcur_t* pcur); - - /** Called after iteratoring over the records. - @return true if invariant satisfied. */ - bool debug() const - { - /* We must find all the index entries on disk. */ - return(UT_LIST_GET_LEN(m_table->indexes) - == m_truncate.indexes()); - } - - /** - Write the TRUNCATE log - @return DB_SUCCESS or error code */ - dberr_t log() const - { - dberr_t err = DB_SUCCESS; - - if (m_log_file_name == 0) { - return(DB_ERROR); - } - - bool ret; - os_file_t handle = os_file_create( - innodb_log_file_key, m_log_file_name, - OS_FILE_CREATE, OS_FILE_NORMAL, - OS_LOG_FILE, srv_read_only_mode, &ret); - if (!ret) { - return(DB_IO_ERROR); - } - - - ulint sz = UNIV_PAGE_SIZE; - void* buf = ut_zalloc_nokey(sz + UNIV_PAGE_SIZE); - if (buf == 0) { - os_file_close(handle); - return(DB_OUT_OF_MEMORY); - } - - /* Align the memory for file i/o if we might have O_DIRECT set*/ - byte* log_buf = static_cast( - ut_align(buf, UNIV_PAGE_SIZE)); - - lsn_t lsn = log_get_lsn(); - - /* Generally loop should exit in single go but - just for those 1% of rare cases we need to assume - corner case. */ - do { - /* First 4 bytes are reserved for magic number - which is currently 0. */ - err = m_truncate.write( - log_buf + 4, log_buf + sz - 4, - m_table->space, m_table->name.m_name, - m_flags, m_table->flags, lsn); - - DBUG_EXECUTE_IF("ib_err_trunc_oom_logging", - err = DB_FAIL;); - - if (err != DB_SUCCESS) { - ut_ad(err == DB_FAIL); - ut_free(buf); - sz *= 2; - buf = ut_zalloc_nokey(sz + UNIV_PAGE_SIZE); - DBUG_EXECUTE_IF("ib_err_trunc_oom_logging", - ut_free(buf); - buf = 0;); - if (buf == 0) { - os_file_close(handle); - return(DB_OUT_OF_MEMORY); - } - log_buf = static_cast( - ut_align(buf, UNIV_PAGE_SIZE)); - } - - } while (err != DB_SUCCESS); - - dberr_t io_err; - - IORequest request(IORequest::WRITE); - - io_err = os_file_write( - request, m_log_file_name, handle, log_buf, 0, sz); - - if (io_err != DB_SUCCESS) { - - ib::error() - << "IO: Failed to write the file size to '" - << m_log_file_name << "'"; - - /* Preserve the original error code */ - if (err == DB_SUCCESS) { - err = io_err; - } - } - - os_file_flush(handle); - os_file_close(handle); - - ut_free(buf); - - /* Why we need MLOG_TRUNCATE when we have truncate_log for - recovery? - - truncate log can protect us if crash happens while truncate - is active. Once truncate is done truncate log is removed. - - If crash happens post truncate and system is yet to - checkpoint, on recovery we would see REDO records from action - before truncate (unless we explicitly checkpoint before - returning from truncate API. Costly alternative so rejected). - - These REDO records may reference a page that doesn't exist - post truncate so we need a mechanism to skip all such REDO - records. MLOG_TRUNCATE records space_id and lsn that exactly - serve the purpose. - - If checkpoint happens post truncate and crash happens post - this point then neither MLOG_TRUNCATE nor REDO record - from action before truncate are accessible. */ - if (!is_system_tablespace(m_table->space)) { - mtr_t mtr; - byte* log_ptr; - - mtr_start(&mtr); - - log_ptr = mlog_open(&mtr, 11 + 8); - log_ptr = mlog_write_initial_log_record_low( - MLOG_TRUNCATE, m_table->space, 0, - log_ptr, &mtr); - - mach_write_to_8(log_ptr, lsn); - log_ptr += 8; - - mlog_close(&mtr, log_ptr); - mtr_commit(&mtr); - } - - return(err); - } - - /** - Indicate completion of truncate log by writing magic-number. - File will be removed from the system but to protect against - unlink (File-System) anomalies we ensure we write magic-number. */ - void done() - { - if (m_log_file_name == 0) { - return; - } - - bool ret; - os_file_t handle = os_file_create_simple_no_error_handling( - innodb_log_file_key, m_log_file_name, - OS_FILE_OPEN, OS_FILE_READ_WRITE, - srv_read_only_mode, &ret); - DBUG_EXECUTE_IF("ib_err_trunc_writing_magic_number", - os_file_close(handle); - ret = false;); - if (!ret) { - ib::error() << "Failed to open truncate log file " - << m_log_file_name << "." - " If server crashes before truncate log is" - " removed make sure it is manually removed" - " before restarting server"; - os_file_delete(innodb_log_file_key, m_log_file_name); - return; - } - - byte buffer[sizeof(TruncateLogger::s_magic)]; - mach_write_to_4(buffer, TruncateLogger::s_magic); - - dberr_t err; - - IORequest request(IORequest::WRITE); - - err = os_file_write( - request, - m_log_file_name, handle, buffer, 0, sizeof(buffer)); - - if (err != DB_SUCCESS) { - - ib::error() - << "IO: Failed to write the magic number to '" - << m_log_file_name << "'"; - } - - DBUG_EXECUTE_IF("ib_trunc_crash_after_updating_magic_no", - DBUG_SUICIDE();); - os_file_flush(handle); - os_file_close(handle); - DBUG_EXECUTE_IF("ib_trunc_crash_after_logging_complete", - log_buffer_flush_to_disk(); - os_thread_sleep(1000000); - DBUG_SUICIDE();); - os_file_delete(innodb_log_file_key, m_log_file_name); - } - -private: - // Disably copying - TruncateLogger(const TruncateLogger&); - TruncateLogger& operator=(const TruncateLogger&); - -private: - /** Lookup the index using the index id. - @return index instance if found else NULL */ - const dict_index_t* find(index_id_t id) const - { - for (const dict_index_t* index = UT_LIST_GET_FIRST( - m_table->indexes); - index != NULL; - index = UT_LIST_GET_NEXT(indexes, index)) { - - if (index->id == id) { - return(index); - } - } - - return(NULL); - } - -private: - /** Table to be truncated */ - dict_table_t* m_table; - - /** Tablespace flags */ - ulint m_flags; - - /** Collect table to truncate information */ - truncate_t m_truncate; - - /** Truncate log file name. */ - char* m_log_file_name; - - -public: - /** Magic Number to indicate truncate action is complete. */ - const static ib_uint32_t s_magic; - - /** Truncate Log file Prefix. */ - const static char* s_log_prefix; - - /** Truncate Log file Extension. */ - const static char* s_log_ext; -}; - -const ib_uint32_t TruncateLogger::s_magic = 32743712; -const char* TruncateLogger::s_log_prefix = "ib_"; -const char* TruncateLogger::s_log_ext = "trunc.log"; - /** Scan to find out truncate log file from the given directory path. @@ -583,9 +254,7 @@ TruncateLogParser::scan( os_file_dir_t dir; os_file_stat_t fileinfo; dberr_t err = DB_SUCCESS; - ulint ext_len = strlen(TruncateLogger::s_log_ext); - ulint prefix_len = strlen(TruncateLogger::s_log_prefix); - ulint dir_len = strlen(dir_path); + const ulint dir_len = strlen(dir_path); /* Scan and look out for the truncate log files. */ dir = os_file_opendir(dir_path, true); @@ -599,12 +268,11 @@ TruncateLogParser::scan( ulint nm_len = strlen(fileinfo.name); if (fileinfo.type == OS_FILE_TYPE_FILE - && nm_len > ext_len + prefix_len - && (0 == strncmp(fileinfo.name + nm_len - ext_len, - TruncateLogger::s_log_ext, ext_len)) - && (0 == strncmp(fileinfo.name, - TruncateLogger::s_log_prefix, - prefix_len))) { + && nm_len > sizeof "ib_trunc.log" + && (0 == strncmp(fileinfo.name + nm_len + - ((sizeof "trunc.log") - 1), + "trunc.log", (sizeof "trunc.log") - 1)) + && (0 == strncmp(fileinfo.name, "ib_", 3))) { if (fileinfo.size == 0) { /* Truncate log not written. Remove the file. */ @@ -614,7 +282,7 @@ TruncateLogParser::scan( } /* Construct file name by appending directory path */ - ulint sz = dir_len + 22 + 22 + 1 + ext_len + prefix_len; + ulint sz = dir_len + 22 + 22 + sizeof "ib_trunc.log"; char* log_file_name = UT_NEW_ARRAY_NOKEY(char, sz); if (log_file_name == NULL) { err = DB_OUT_OF_MEMORY; @@ -687,8 +355,7 @@ TruncateLogParser::parse( break; } - ulint magic_n = mach_read_from_4(log_buf); - if (magic_n == TruncateLogger::s_magic) { + if (mach_read_from_4(log_buf) == 32743712) { /* Truncate action completed. Avoid parsing the file. */ os_file_close(handle); @@ -884,58 +551,6 @@ private: bool m_table_found; }; -/** -@param mtr mini-transaction covering the read -@param pcur persistent cursor used for reading -@return DB_SUCCESS or error code */ -dberr_t -TruncateLogger::operator()(mtr_t* mtr, btr_pcur_t* pcur) -{ - ulint len; - const byte* field; - rec_t* rec = btr_pcur_get_rec(pcur); - truncate_t::index_t index; - - field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_INDEXES__TYPE, &len); - ut_ad(len == 4); - index.m_type = mach_read_from_4(field); - - field = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__ID, &len); - ut_ad(len == 8); - index.m_id = mach_read_from_8(field); - - field = rec_get_nth_field_old( - rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len); - ut_ad(len == 4); - index.m_root_page_no = mach_read_from_4(field); - - /* For compressed tables we need to store extra meta-data - required during btr_create(). */ - if (FSP_FLAGS_GET_ZIP_SSIZE(m_flags)) { - - const dict_index_t* dict_index = find(index.m_id); - - if (dict_index != NULL) { - - dberr_t err = index.set(dict_index); - - if (err != DB_SUCCESS) { - m_truncate.clear(); - return(err); - } - - } else { - ib::warn() << "Index id " << index.m_id - << " not found"; - } - } - - m_truncate.add(index); - - return(DB_SUCCESS); -} - /** Drop an index in the table. @@ -1121,251 +736,6 @@ TableLocator::operator()(mtr_t* mtr, btr_pcur_t* pcur) return(DB_SUCCESS); } -/** -Rollback the transaction and release the index locks. -Drop indexes if table is corrupted so that drop/create -sequence works as expected. - -@param table table to truncate -@param trx transaction covering the TRUNCATE -@param new_id new table id that was suppose to get assigned - to the table if truncate executed successfully. -@param has_internal_doc_id indicate existence of fts index -@param no_redo if true, turn-off redo logging -@param corrupted table corrupted status -@param unlock_index if true then unlock indexes before action */ -static -void -row_truncate_rollback( - dict_table_t* table, - trx_t* trx, - table_id_t new_id, - bool has_internal_doc_id, - bool no_redo, - bool corrupted, - bool unlock_index) -{ - if (unlock_index) { - dict_table_x_unlock_indexes(table); - } - - trx->error_state = DB_SUCCESS; - - trx_rollback_to_savepoint(trx, NULL); - - trx->error_state = DB_SUCCESS; - - if (corrupted && !dict_table_is_temporary(table)) { - - /* Cleanup action to ensure we don't left over stale entries - if we are marking table as corrupted. This will ensure - it can be recovered using drop/create sequence. */ - dict_table_x_lock_indexes(table); - - DropIndex dropIndex(table, no_redo); - - SysIndexIterator().for_each(dropIndex); - - dict_table_x_unlock_indexes(table); - - for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); - index != NULL; - index = UT_LIST_GET_NEXT(indexes, index)) { - - dict_set_corrupted(index, trx, "TRUNCATE TABLE"); - } - - if (has_internal_doc_id) { - - ut_ad(!trx_is_started(trx)); - - table_id_t id = table->id; - - table->id = new_id; - - fts_drop_tables(trx, table); - - table->id = id; - - ut_ad(trx_is_started(trx)); - - trx_commit_for_mysql(trx); - } - - } else if (corrupted && dict_table_is_temporary(table)) { - - dict_table_x_lock_indexes(table); - - for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); - index != NULL; - index = UT_LIST_GET_NEXT(indexes, index)) { - - dict_drop_index_tree_in_mem(index, index->page); - - index->page = FIL_NULL; - } - - dict_table_x_unlock_indexes(table); - } - - table->corrupted = corrupted; -} - -/** -Finish the TRUNCATE operations for both commit and rollback. - -@param table table being truncated -@param trx transaction covering the truncate -@param fsp_flags tablespace flags -@param logger table to truncate information logger -@param err status of truncate operation - -@return DB_SUCCESS or error code */ -static MY_ATTRIBUTE((warn_unused_result)) -dberr_t -row_truncate_complete( - dict_table_t* table, - trx_t* trx, - ulint fsp_flags, - TruncateLogger* &logger, - dberr_t err) -{ - bool is_file_per_table = dict_table_is_file_per_table(table); - - /* Add the table back to FTS optimize background thread. */ - if (table->fts) { - fts_optimize_add_table(table); - } - - row_mysql_unlock_data_dictionary(trx); - - DEBUG_SYNC_C("ib_trunc_table_trunc_completing"); - - if (!dict_table_is_temporary(table)) { - - DBUG_EXECUTE_IF("ib_trunc_crash_before_log_removal", - log_buffer_flush_to_disk(); - os_thread_sleep(500000); - DBUG_SUICIDE();); - - /* Note: We don't log-checkpoint instead we have written - a special REDO log record MLOG_TRUNCATE that is used to - avoid applying REDO records before truncate for crash - that happens post successful truncate completion. */ - - if (logger != NULL) { - logger->done(); - UT_DELETE(logger); - logger = NULL; - } - } - - /* If non-temp file-per-table tablespace... */ - if (is_file_per_table - && !dict_table_is_temporary(table) - && fsp_flags != ULINT_UNDEFINED) { - - /* This function will reset back the stop_new_ops - and is_being_truncated so that fil-ops can re-start. */ - dberr_t err2 = truncate_t::truncate( - table->space, - table->data_dir_path, - table->name.m_name, fsp_flags, false); - - if (err2 != DB_SUCCESS) { - return(err2); - } - } - - if (err == DB_SUCCESS) { - dict_stats_update(table, DICT_STATS_EMPTY_TABLE); - } - - trx->op_info = ""; - - /* For temporary tables or if there was an error, we need to reset - the dict operation flags. */ - trx->ddl = false; - trx->dict_operation = TRX_DICT_OP_NONE; - - ut_ad(!trx_is_started(trx)); - - srv_wake_master_thread(); - - DBUG_EXECUTE_IF("ib_trunc_crash_after_truncate_done", - DBUG_SUICIDE();); - - return(err); -} - -/** -Handle FTS truncate issues. -@param table table being truncated -@param new_id new id for the table -@param trx transaction covering the truncate -@return DB_SUCCESS or error code. */ -static MY_ATTRIBUTE((warn_unused_result)) -dberr_t -row_truncate_fts( - dict_table_t* table, - table_id_t new_id, - trx_t* trx) -{ - dict_table_t fts_table; - - fts_table.id = new_id; - fts_table.name = table->name; - fts_table.flags2 = table->flags2; - fts_table.flags = table->flags; - fts_table.space = table->space; - - /* table->data_dir_path is used for FTS AUX table - creation. */ - if (DICT_TF_HAS_DATA_DIR(table->flags) - && table->data_dir_path == NULL) { - dict_get_and_save_data_dir_path(table, true); - ut_ad(table->data_dir_path != NULL); - } - - fts_table.data_dir_path = table->data_dir_path; - - dberr_t err; - - err = fts_create_common_tables( - trx, &fts_table, table->name.m_name, TRUE); - - for (ulint i = 0; - i < ib_vector_size(table->fts->indexes) && err == DB_SUCCESS; - i++) { - - dict_index_t* fts_index; - - fts_index = static_cast( - ib_vector_getp(table->fts->indexes, i)); - - err = fts_create_index_tables_low( - trx, fts_index, table->name.m_name, new_id); - } - - DBUG_EXECUTE_IF("ib_err_trunc_during_fts_trunc", - err = DB_ERROR;); - - if (err != DB_SUCCESS) { - - trx->error_state = DB_SUCCESS; - trx_rollback_to_savepoint(trx, NULL); - trx->error_state = DB_SUCCESS; - - ib::error() << "Unable to truncate FTS index for table " - << table->name; - } else { - - ut_ad(trx_is_started(trx)); - } - - return(err); -} - /** Update system table to reflect new table id. @param old_table_id old table id @@ -1506,629 +876,6 @@ row_truncate_update_sys_tables_during_fix_up( return(err); } -/** -Truncate also results in assignment of new table id, update the system -SYSTEM TABLES with the new id. -@param table, table being truncated -@param new_id, new table id -@param has_internal_doc_id, has doc col (fts) -@param no_redo if true, turn-off redo logging -@param trx transaction handle -@return error code or DB_SUCCESS */ -static MY_ATTRIBUTE((warn_unused_result)) -dberr_t -row_truncate_update_system_tables( - dict_table_t* table, - table_id_t new_id, - bool has_internal_doc_id, - bool no_redo, - trx_t* trx) -{ - dberr_t err = DB_SUCCESS; - - ut_a(!dict_table_is_temporary(table)); - - err = row_truncate_update_table_id(table->id, new_id, FALSE, trx); - - DBUG_EXECUTE_IF("ib_err_trunc_during_sys_table_update", - err = DB_ERROR;); - - if (err != DB_SUCCESS) { - - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, true, false); - - ib::error() << "Unable to assign a new identifier to table " - << table->name << " after truncating it. Marked the" - " table as corrupted. In-memory representation is now" - " different from the on-disk representation."; - err = DB_ERROR; - } else { - /* Drop the old FTS index */ - if (has_internal_doc_id) { - - ut_ad(trx_is_started(trx)); - - fts_drop_tables(trx, table); - - DBUG_EXECUTE_IF("ib_truncate_crash_while_fts_cleanup", - DBUG_SUICIDE();); - - ut_ad(trx_is_started(trx)); - } - - DBUG_EXECUTE_IF("ib_trunc_crash_after_fts_drop", - log_buffer_flush_to_disk(); - os_thread_sleep(2000000); - DBUG_SUICIDE();); - - dict_table_change_id_in_cache(table, new_id); - - /* Reset the Doc ID in cache to 0 */ - if (has_internal_doc_id && table->fts->cache != NULL) { - DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear", - os_thread_sleep(10000000);); - - table->fts->fts_status |= TABLE_DICT_LOCKED; - fts_update_next_doc_id(trx, table, NULL, 0); - fts_cache_clear(table->fts->cache); - fts_cache_init(table->fts->cache); - table->fts->fts_status &= uint(~TABLE_DICT_LOCKED); - } - } - - return(err); -} - -/** -Prepare for the truncate process. On success all of the table's indexes will -be locked in X mode. -@param table table to truncate -@param flags tablespace flags -@return error code or DB_SUCCESS */ -static MY_ATTRIBUTE((warn_unused_result)) -dberr_t -row_truncate_prepare(dict_table_t* table, ulint* flags) -{ - ut_ad(!dict_table_is_temporary(table)); - ut_ad(dict_table_is_file_per_table(table)); - - *flags = fil_space_get_flags(table->space); - - ut_ad(!dict_table_is_temporary(table)); - - dict_get_and_save_data_dir_path(table, true); - - if (*flags != ULINT_UNDEFINED) { - - dberr_t err = fil_prepare_for_truncate(table->space); - - if (err != DB_SUCCESS) { - return(err); - } - } - - return(DB_SUCCESS); -} - -/** -Do foreign key checks before starting TRUNCATE. -@param table table being truncated -@param trx transaction covering the truncate -@return DB_SUCCESS or error code */ -static MY_ATTRIBUTE((warn_unused_result)) -dberr_t -row_truncate_foreign_key_checks( - const dict_table_t* table, - const trx_t* trx) -{ - /* Check if the table is referenced by foreign key constraints from - some other table (not the table itself) */ - - dict_foreign_set::iterator it - = std::find_if(table->referenced_set.begin(), - table->referenced_set.end(), - dict_foreign_different_tables()); - - if (!srv_read_only_mode - && it != table->referenced_set.end() - && trx->check_foreigns) { - - dict_foreign_t* foreign = *it; - - FILE* ef = dict_foreign_err_file; - - /* We only allow truncating a referenced table if - FOREIGN_KEY_CHECKS is set to 0 */ - - mutex_enter(&dict_foreign_err_mutex); - - rewind(ef); - - ut_print_timestamp(ef); - - fputs(" Cannot truncate table ", ef); - ut_print_name(ef, trx, table->name.m_name); - fputs(" by DROP+CREATE\n" - "InnoDB: because it is referenced by ", ef); - ut_print_name(ef, trx, foreign->foreign_table_name); - putc('\n', ef); - - mutex_exit(&dict_foreign_err_mutex); - - return(DB_ERROR); - } - - /* TODO: could we replace the counter n_foreign_key_checks_running - with lock checks on the table? Acquire here an exclusive lock on the - table, and rewrite lock0lock.cc and the lock wait in srv0srv.cc so that - they can cope with the table having been truncated here? Foreign key - checks take an IS or IX lock on the table. */ - - if (table->n_foreign_key_checks_running > 0) { - ib::warn() << "Cannot truncate table " << table->name - << " because there is a foreign key check running on" - " it."; - - return(DB_ERROR); - } - - return(DB_SUCCESS); -} - -/** -Do some sanity checks before starting the actual TRUNCATE. -@param table table being truncated -@return DB_SUCCESS or error code */ -static MY_ATTRIBUTE((warn_unused_result)) -dberr_t -row_truncate_sanity_checks( - const dict_table_t* table) -{ - if (dict_table_is_discarded(table)) { - - return(DB_TABLESPACE_DELETED); - - } else if (!table->is_readable()) { - if (fil_space_get(table->space) == NULL) { - return(DB_TABLESPACE_NOT_FOUND); - - } else { - return(DB_DECRYPTION_FAILED); - } - } else if (dict_table_is_corrupted(table)) { - - return(DB_TABLE_CORRUPT); - } - - return(DB_SUCCESS); -} - -/** -Truncates a table for MySQL. -@param table table being truncated -@param trx transaction covering the truncate -@return error code or DB_SUCCESS */ -dberr_t -row_truncate_table_for_mysql( - dict_table_t* table, - trx_t* trx) -{ - bool is_file_per_table = dict_table_is_file_per_table(table); - dberr_t err; -#ifdef UNIV_DEBUG - ulint old_space = table->space; -#endif /* UNIV_DEBUG */ - TruncateLogger* logger = NULL; - - /* Understanding the truncate flow. - - Step-1: Perform intiial sanity check to ensure table can be truncated. - This would include check for tablespace discard status, ibd file - missing, etc .... - - Step-2: Start transaction (only for non-temp table as temp-table don't - modify any data on disk doesn't need transaction object). - - Step-3: Validate ownership of needed locks (Exclusive lock). - Ownership will also ensure there is no active SQL queries, INSERT, - SELECT, ..... - - Step-4: Stop all the background process associated with table. - - Step-5: There are few foreign key related constraint under which - we can't truncate table (due to referential integrity unless it is - turned off). Ensure this condition is satisfied. - - Step-6: Truncate operation can be rolled back in case of error - till some point. Associate rollback segment to record undo log. - - Step-7: Generate new table-id. - Why we need new table-id ? - Purge and rollback case: we assign a new table id for the table. - Since purge and rollback look for the table based on the table id, - they see the table as 'dropped' and discard their operations. - - Step-8: Log information about tablespace which includes - table and index information. If there is a crash in the next step - then during recovery we will attempt to fixup the operation. - - Step-9: Drop all indexes (this include freeing of the pages - associated with them). - - Step-10: Re-create new indexes. - - Step-11: Update new table-id to in-memory cache (dictionary), - on-disk (INNODB_SYS_TABLES). INNODB_SYS_INDEXES also needs to - be updated to reflect updated root-page-no of new index created - and updated table-id. - - Step-12: Cleanup Stage. Reset auto-inc value to 1. - Release all the locks. - Commit the transaction. Update trx operation state. - - Notes: - - On error, log checkpoint is done followed writing of magic number to - truncate log file. If servers crashes after truncate, fix-up action - will not be applied. - - - log checkpoint is done before starting truncate table to ensure - that previous REDO log entries are not applied if current truncate - crashes. Consider following use-case: - - create table .... insert/load table .... truncate table (crash) - - on restart table is restored .... truncate table (crash) - - on restart (assuming default log checkpoint is not done) will have - 2 REDO log entries for same table. (Note 2 REDO log entries - for different table is not an issue). - For system-tablespace we can't truncate the tablespace so we need - to initiate a local cleanup that involves dropping of indexes and - re-creating them. If we apply stale entry we might end-up issuing - drop on wrong indexes. - - - Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE, - so we do not have to remove insert buffer records, as the - insert buffer works at a low level. If a freed page is later - reallocated, the allocator will remove the ibuf entries for - it. When we prepare to truncate *.ibd files, we remove all entries - for the table in the insert buffer tree. This is not strictly - necessary, but we can free up some space in the system tablespace. - - - Linear readahead and random readahead: we use the same - method as in 3) to discard ongoing operations. (This is only - relevant for TRUNCATE TABLE by TRUNCATE TABLESPACE.) - Ensure that the table will be dropped by trx_rollback_active() in - case of a crash. - */ - - /*-----------------------------------------------------------------*/ - /* Step-1: Perform intiial sanity check to ensure table can be - truncated. This would include check for tablespace discard status, - ibd file missing, etc .... */ - err = row_truncate_sanity_checks(table); - if (err != DB_SUCCESS) { - return(err); - - } - - /* Step-2: Start transaction (only for non-temp table as temp-table - don't modify any data on disk doesn't need transaction object). */ - if (!dict_table_is_temporary(table)) { - if (table->fts) { - fts_optimize_remove_table(table); - } - - /* Avoid transaction overhead for temporary table DDL. */ - trx_start_for_ddl(trx, TRX_DICT_OP_TABLE); - } - - DEBUG_SYNC_C("row_trunc_before_dict_lock"); - - /* Step-3: Validate ownership of needed locks (Exclusive lock). - Ownership will also ensure there is no active SQL queries, INSERT, - SELECT, .....*/ - trx->op_info = "truncating table"; - ut_a(trx->dict_operation_lock_mode == 0); - row_mysql_lock_data_dictionary(trx); - ut_ad(mutex_own(&dict_sys->mutex)); - ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X)); - - /* Step-4: Stop all the background process associated with table. */ - dict_stats_wait_bg_to_stop_using_table(table, trx); - - /* Step-5: There are few foreign key related constraint under which - we can't truncate table (due to referential integrity unless it is - turned off). Ensure this condition is satisfied. */ - ulint fsp_flags = ULINT_UNDEFINED; - err = row_truncate_foreign_key_checks(table, trx); - if (err != DB_SUCCESS) { - trx_rollback_to_savepoint(trx, NULL); - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - - /* Remove all locks except the table-level X lock. */ - lock_remove_all_on_table(table, FALSE); - trx->table_id = table->id; - trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); - - /* Step-6: Truncate operation can be rolled back in case of error - till some point. Associate rollback segment to record undo log. */ - if (!dict_table_is_temporary(table)) { - mutex_enter(&trx->undo_mutex); - - trx_undo_t** pundo = &trx->rsegs.m_redo.update_undo; - err = trx_undo_assign_undo( - trx, trx->rsegs.m_redo.rseg, pundo, TRX_UNDO_UPDATE); - - mutex_exit(&trx->undo_mutex); - - DBUG_EXECUTE_IF("ib_err_trunc_assigning_undo_log", - err = DB_ERROR;); - if (err != DB_SUCCESS) { - trx_rollback_to_savepoint(trx, NULL); - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - } - - /* Step-7: Generate new table-id. - Why we need new table-id ? - Purge and rollback: we assign a new table id for the - table. Since purge and rollback look for the table based on - the table id, they see the table as 'dropped' and discard - their operations. */ - table_id_t new_id; - dict_hdr_get_new_id(&new_id, NULL, NULL, table, false); - - /* Check if table involves FTS index. */ - bool has_internal_doc_id = - dict_table_has_fts_index(table) - || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID); - - bool no_redo = is_file_per_table && !has_internal_doc_id; - - /* Step-8: Log information about tablespace which includes - table and index information. If there is a crash in the next step - then during recovery we will attempt to fixup the operation. */ - - /* Lock all index trees for this table, as we will truncate - the table/index and possibly change their metadata. All - DML/DDL are blocked by table level X lock, with a few exceptions - such as queries into information schema about the table, - MySQL could try to access index stats for this kind of query, - we need to use index locks to sync up */ - dict_table_x_lock_indexes(table); - - if (!dict_table_is_temporary(table)) { - - if (is_file_per_table) { - - err = row_truncate_prepare(table, &fsp_flags); - - DBUG_EXECUTE_IF("ib_err_trunc_preparing_for_truncate", - err = DB_ERROR;); - - if (err != DB_SUCCESS) { - row_truncate_rollback( - table, trx, new_id, - has_internal_doc_id, - no_redo, false, true); - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - } else { - fsp_flags = fil_space_get_flags(table->space); - - DBUG_EXECUTE_IF("ib_err_trunc_preparing_for_truncate", - fsp_flags = ULINT_UNDEFINED;); - - if (fsp_flags == ULINT_UNDEFINED) { - row_truncate_rollback( - table, trx, new_id, - has_internal_doc_id, - no_redo, false, true); - return(row_truncate_complete( - table, trx, fsp_flags, - logger, DB_ERROR)); - } - } - - logger = UT_NEW_NOKEY(TruncateLogger( - table, fsp_flags, new_id)); - - err = logger->init(); - if (err != DB_SUCCESS) { - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, false, true); - return(row_truncate_complete( - table, trx, fsp_flags, logger, DB_ERROR)); - - } - - err = SysIndexIterator().for_each(*logger); - if (err != DB_SUCCESS) { - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, false, true); - return(row_truncate_complete( - table, trx, fsp_flags, logger, DB_ERROR)); - - } - - ut_ad(logger->debug()); - - err = logger->log(); - - if (err != DB_SUCCESS) { - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, false, true); - return(row_truncate_complete( - table, trx, fsp_flags, logger, DB_ERROR)); - } - } - - DBUG_EXECUTE_IF("ib_trunc_crash_after_redo_log_write_complete", - log_buffer_flush_to_disk(); - os_thread_sleep(3000000); - DBUG_SUICIDE();); - - /* Step-9: Drop all indexes (free index pages associated with these - indexes) */ - if (!dict_table_is_temporary(table)) { - - DropIndex dropIndex(table, no_redo); - - err = SysIndexIterator().for_each(dropIndex); - - if (err != DB_SUCCESS) { - - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, true, true); - - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - } else { - /* For temporary tables we don't have entries in SYSTEM TABLES*/ - ut_ad(fsp_is_system_temporary(table->space)); - for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes); - index != NULL; - index = UT_LIST_GET_NEXT(indexes, index)) { - - err = dict_truncate_index_tree_in_mem(index); - - if (err != DB_SUCCESS) { - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, true, true); - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - - DBUG_EXECUTE_IF( - "ib_trunc_crash_during_drop_index_temp_table", - log_buffer_flush_to_disk(); - os_thread_sleep(2000000); - DBUG_SUICIDE();); - } - } - - if (is_file_per_table && fsp_flags != ULINT_UNDEFINED) { - /* A single-table tablespace has initially - FIL_IBD_FILE_INITIAL_SIZE number of pages allocated and an - extra page is allocated for each of the indexes present. But in - the case of clust index 2 pages are allocated and as one is - covered in the calculation as part of table->indexes.count we - take care of the other page by adding 1. */ - ulint space_size = table->indexes.count + - FIL_IBD_FILE_INITIAL_SIZE + 1; - - if (has_internal_doc_id) { - /* Since aux tables are created for fts indexes and - they use seperate tablespaces. */ - space_size -= ib_vector_size(table->fts->indexes); - } - - fil_reinit_space_header_for_table(table, space_size, trx); - } - - DBUG_EXECUTE_IF("ib_trunc_crash_with_intermediate_log_checkpoint", - log_buffer_flush_to_disk(); - os_thread_sleep(2000000); - log_checkpoint(TRUE, TRUE); - os_thread_sleep(1000000); - DBUG_SUICIDE();); - - DBUG_EXECUTE_IF("ib_trunc_crash_drop_reinit_done_create_to_start", - log_buffer_flush_to_disk(); - os_thread_sleep(2000000); - DBUG_SUICIDE();); - - /* Step-10: Re-create new indexes. */ - if (!dict_table_is_temporary(table)) { - - CreateIndex createIndex(table, no_redo); - - err = SysIndexIterator().for_each(createIndex); - - if (err != DB_SUCCESS) { - - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, true, true); - - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - } - - /* Done with index truncation, release index tree locks, - subsequent work relates to table level metadata change */ - dict_table_x_unlock_indexes(table); - - if (has_internal_doc_id) { - - err = row_truncate_fts(table, new_id, trx); - - if (err != DB_SUCCESS) { - - row_truncate_rollback( - table, trx, new_id, has_internal_doc_id, - no_redo, true, false); - - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - } - - /* Step-11: Update new table-id to in-memory cache (dictionary), - on-disk (INNODB_SYS_TABLES). INNODB_SYS_INDEXES also needs to - be updated to reflect updated root-page-no of new index created - and updated table-id. */ - if (dict_table_is_temporary(table)) { - - dict_table_change_id_in_cache(table, new_id); - err = DB_SUCCESS; - - } else { - - /* If this fails then we are in an inconsistent state and - the results are undefined. */ - ut_ad(old_space == table->space); - - err = row_truncate_update_system_tables( - table, new_id, has_internal_doc_id, no_redo, trx); - - if (err != DB_SUCCESS) { - return(row_truncate_complete( - table, trx, fsp_flags, logger, err)); - } - } - - DBUG_EXECUTE_IF("ib_trunc_crash_on_updating_dict_sys_info", - log_buffer_flush_to_disk(); - os_thread_sleep(2000000); - DBUG_SUICIDE();); - - /* Step-12: Cleanup Stage. Reset auto-inc value to 1. - Release all the locks. - Commit the transaction. Update trx operation state. */ - dict_table_autoinc_lock(table); - dict_table_autoinc_initialize(table, 1); - dict_table_autoinc_unlock(table); - - if (trx_is_started(trx)) { - - trx_commit_for_mysql(trx); - } - - return(row_truncate_complete(table, trx, fsp_flags, logger, err)); -} - /** Fix the table truncate by applying information parsed from TRUNCATE log. Fix-up includes re-creating table (drop and re-create indexes) @@ -3056,4 +1803,3 @@ truncate_t::write( return(DB_SUCCESS); } - diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index d50d86ac338..2e0ef551442 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -354,8 +354,8 @@ row_undo_ins_parse_undo_rec( close_table: /* Normally, tables should not disappear or become unaccessible during ROLLBACK, because they should be - protected by InnoDB table locks. TRUNCATE TABLE - or table corruption could be valid exceptions. + protected by InnoDB table locks. Corruption could be + a valid exception. FIXME: When running out of temporary tablespace, it would probably be better to just drop all temporary diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 8955eab639c..3b87c3ae1b7 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -1152,8 +1152,8 @@ row_undo_mod_parse_undo_rec( close_table: /* Normally, tables should not disappear or become unaccessible during ROLLBACK, because they should be - protected by InnoDB table locks. TRUNCATE TABLE - or table corruption could be valid exceptions. + protected by InnoDB table locks. Corruption could be + a valid exception. FIXME: When running out of temporary tablespace, it would probably be better to just drop all temporary diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 171e06894ca..342f0d222e0 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -286,34 +286,6 @@ row_upd_check_references_constraints( FALSE, FALSE, DICT_ERR_IGNORE_NONE); } - /* dict_operation_lock is held both here - (UPDATE or DELETE with FOREIGN KEY) and by TRUNCATE - TABLE operations. - If a TRUNCATE TABLE operation is in progress, - there can be 2 possible conditions: - 1) row_truncate_table_for_mysql() is not yet called. - 2) Truncate releases dict_operation_lock - during eviction of pages from buffer pool - for a file-per-table tablespace. - - In case of (1), truncate will wait for FK operation - to complete. - In case of (2), truncate will be rolled forward even - if it is interrupted. So if the foreign table is - undergoing a truncate, ignore the FK check. */ - - if (foreign_table) { - mutex_enter(&fil_system->mutex); - const fil_space_t* space = fil_space_get_by_id( - foreign_table->space); - const bool being_truncated = space - && space->is_being_truncated; - mutex_exit(&fil_system->mutex); - if (being_truncated) { - continue; - } - } - /* NOTE that if the thread ends up waiting for a lock we will release dict_operation_lock temporarily! But the counter on the table protects 'foreign' from diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index d59d260940e..cda652a9855 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1107,8 +1107,7 @@ srv_undo_tablespaces_init(bool create_new_db) buf_LRU_flush_or_remove_pages(*it, &dummy2); /* Remove the truncate redo log file. */ - undo::Truncate undo_trunc; - undo_trunc.done_logging(*it); + undo::done(*it); } } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 012ac9684dd..c5f7b6c895b 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -536,18 +536,22 @@ truncate of the UNDO is in progress. This file is required during recovery to complete the truncate. */ namespace undo { + /** Magic Number to indicate truncate action is complete. */ + static const ib_uint32_t s_magic = 76845412; /** Populate log file name based on space_id @param[in] space_id id of the undo tablespace. @return DB_SUCCESS or error code */ - dberr_t populate_log_file_name( + static dberr_t populate_log_file_name( ulint space_id, char*& log_file_name) { - ulint log_file_name_sz = - strlen(srv_log_group_home_dir) + 22 + 1 /* NUL */ - + strlen(undo::s_log_prefix) - + strlen(undo::s_log_ext); + static const char s_log_prefix[] = "undo_"; + static const char s_log_ext[] = "trunc.log"; + + ulint log_file_name_sz = strlen(srv_log_group_home_dir) + + (22 - 1 /* NUL */ + + sizeof s_log_prefix + sizeof s_log_ext); log_file_name = new (std::nothrow) char[log_file_name_sz]; if (log_file_name == 0) { @@ -569,63 +573,12 @@ namespace undo { snprintf(log_file_name + log_file_name_len, log_file_name_sz - log_file_name_len, - "%s%lu_%s", undo::s_log_prefix, - (ulong) space_id, s_log_ext); + "%s" ULINTPF "_%s", s_log_prefix, + space_id, s_log_ext); return(DB_SUCCESS); } - /** Create the truncate log file. - @param[in] space_id id of the undo tablespace to truncate. - @return DB_SUCCESS or error code. */ - dberr_t init(ulint space_id) - { - dberr_t err; - char* log_file_name; - - /* Step-1: Create the log file name using the pre-decided - prefix/suffix and table id of undo tablepsace to truncate. */ - err = populate_log_file_name(space_id, log_file_name); - if (err != DB_SUCCESS) { - return(err); - } - - /* Step-2: Create the log file, open it and write 0 to - indicate init phase. */ - bool ret; - os_file_t handle = os_file_create( - innodb_log_file_key, log_file_name, OS_FILE_CREATE, - OS_FILE_NORMAL, OS_LOG_FILE, srv_read_only_mode, &ret); - if (!ret) { - delete[] log_file_name; - return(DB_IO_ERROR); - } - - ulint sz = UNIV_PAGE_SIZE; - void* buf = ut_zalloc_nokey(sz + UNIV_PAGE_SIZE); - if (buf == NULL) { - os_file_close(handle); - delete[] log_file_name; - return(DB_OUT_OF_MEMORY); - } - - byte* log_buf = static_cast( - ut_align(buf, UNIV_PAGE_SIZE)); - - IORequest request(IORequest::WRITE); - - err = os_file_write( - request, log_file_name, handle, log_buf, 0, sz); - - os_file_flush(handle); - os_file_close(handle); - - ut_free(buf); - delete[] log_file_name; - - return(err); - } - /** Mark completion of undo truncate action by writing magic number to the log file and then removing it from the disk. If we are going to remove it from disk then why write magic number ? @@ -998,43 +951,140 @@ trx_purge_initiate_truncate( /* Step-3: Start the actual truncate. - a. log-checkpoint - b. Write the DDL log to protect truncate action from CRASH - c. Remove rseg instance if added to purge queue before we + a. Remove rseg instance if added to purge queue before we initiate truncate. - d. Execute actual truncate - e. Remove the DDL log. */ - - /* After truncate if server crashes then redo logging done for this - undo tablespace might not stand valid as tablespace has been - truncated. */ - log_make_checkpoint_at(LSN_MAX, TRUE); + b. Execute actual truncate */ const ulint space_id = undo_trunc->get_marked_space_id(); ib::info() << "Truncating UNDO tablespace " << space_id; -#ifdef UNIV_DEBUG - dberr_t err = -#endif /* UNIV_DEBUG */ - undo_trunc->start_logging(space_id); - ut_ad(err == DB_SUCCESS); - - DBUG_EXECUTE_IF("ib_undo_trunc_before_truncate", - ib::info() << "ib_undo_trunc_before_truncate"; - DBUG_SUICIDE();); - trx_purge_cleanse_purge_queue(undo_trunc); - if (!trx_undo_truncate_tablespace(undo_trunc)) { - /* Note: In case of error we don't enable the rsegs - and neither unmark the tablespace so the tablespace - continue to remain inactive. */ - ib::error() << "Failed to truncate UNDO tablespace " - << space_id; + ut_a(srv_is_undo_tablespace(space_id)); + + /* Flush all to-be-discarded pages of the tablespace. + + During truncation, we do not want any writes to the + to-be-discarded area, because we must set the space->size + early in order to have deterministic page allocation. + + If a log checkpoint was completed at LSN earlier than our + mini-transaction commit and the server was killed, then + discarding the to-be-trimmed pages without flushing would + break crash recovery. So, we cannot avoid the write. */ + { + FlushObserver observer( + space_id, + UT_LIST_GET_FIRST(purge_sys->query->thrs)->graph->trx, + NULL); + buf_LRU_flush_or_remove_pages(space_id, &observer); + } + + log_free_check(); + + /* Adjust the tablespace metadata. */ + fil_space_t* space = fil_truncate_prepare(space_id); + + if (!space) { + ib::error() << "Failed to find UNDO tablespace " << space_id; return; } + /* Undo tablespace always are a single file. */ + ut_a(UT_LIST_GET_LEN(space->chain) == 1); + fil_node_t* file = UT_LIST_GET_FIRST(space->chain); + /* The undo tablespace files are never closed. */ + ut_ad(file->is_open()); + + /* Re-initialize tablespace, in a single mini-transaction. */ + mtr_t mtr; + const ulint size = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES; + mtr.start(); + mtr_x_lock(&space->latch, &mtr); + fil_truncate_log(space, size, &mtr); + fsp_header_init(space_id, size, &mtr); + mutex_enter(&fil_system->mutex); + space->size = file->size = size; + mutex_exit(&fil_system->mutex); + + for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) { + trx_rsegf_t* rseg_header; + + trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i); + + rseg->page_no = trx_rseg_header_create( + space_id, ULINT_MAX, rseg->id, &mtr); + + rseg_header = trx_rsegf_get_new(space_id, rseg->page_no, &mtr); + + /* Before re-initialization ensure that we free the existing + structure. There can't be any active transactions. */ + ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0); + ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0); + + trx_undo_t* next_undo; + + for (trx_undo_t* undo = + UT_LIST_GET_FIRST(rseg->update_undo_cached); + undo != NULL; + undo = next_undo) { + + next_undo = UT_LIST_GET_NEXT(undo_list, undo); + UT_LIST_REMOVE(rseg->update_undo_cached, undo); + MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED); + trx_undo_mem_free(undo); + } + + for (trx_undo_t* undo = + UT_LIST_GET_FIRST(rseg->insert_undo_cached); + undo != NULL; + undo = next_undo) { + + next_undo = UT_LIST_GET_NEXT(undo_list, undo); + UT_LIST_REMOVE(rseg->insert_undo_cached, undo); + MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED); + trx_undo_mem_free(undo); + } + + UT_LIST_INIT(rseg->update_undo_list, &trx_undo_t::undo_list); + UT_LIST_INIT(rseg->update_undo_cached, &trx_undo_t::undo_list); + UT_LIST_INIT(rseg->insert_undo_list, &trx_undo_t::undo_list); + UT_LIST_INIT(rseg->insert_undo_cached, &trx_undo_t::undo_list); + + /* These were written by trx_rseg_header_create(). */ + ut_ad(mach_read_from_4(rseg_header + TRX_RSEG_MAX_SIZE) + == uint32_t(rseg->max_size)); + ut_ad(!mach_read_from_4(rseg_header + TRX_RSEG_HISTORY_SIZE)); + + rseg->max_size = ULINT_MAX; + + /* Initialize the undo log lists according to the rseg header */ + rseg->curr_size = 1; + rseg->trx_ref_count = 0; + rseg->last_page_no = FIL_NULL; + rseg->last_offset = 0; + rseg->last_trx_no = 0; + rseg->last_del_marks = FALSE; + } + + mtr.commit(); + /* Write-ahead the redo log record. */ + log_write_up_to(mtr.commit_lsn(), true); + + /* Trim the file size. */ + os_file_truncate(file->name, file->handle, + os_offset_t(size) << srv_page_size_shift, true); + + /* TODO: PUNCH_HOLE the garbage (with write-ahead logging) */ + + mutex_enter(&fil_system->mutex); + ut_ad(space->stop_new_ops); + ut_ad(space->is_being_truncated); + space->stop_new_ops = false; + space->is_being_truncated = false; + mutex_exit(&fil_system->mutex); + if (purge_sys->rseg != NULL && purge_sys->rseg->last_page_no == FIL_NULL) { /* If purge_sys->rseg is pointing to rseg that was recently @@ -1048,14 +1098,11 @@ trx_purge_initiate_truncate( purge_sys->rseg = NULL; } - DBUG_EXECUTE_IF("ib_undo_trunc_before_ddl_log_end", - ib::info() << "ib_undo_trunc_before_ddl_log_end"; + DBUG_EXECUTE_IF("ib_undo_trunc", + ib::info() << "ib_undo_trunc"; + log_write_up_to(LSN_MAX, true); DBUG_SUICIDE();); - log_make_checkpoint_at(LSN_MAX, TRUE); - - undo_trunc->done_logging(space_id); - /* Completed truncate. Now it is safe to re-use the tablespace. */ for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) { trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i); @@ -1066,10 +1113,6 @@ trx_purge_initiate_truncate( undo_trunc->reset(); undo::Truncate::clear_trunc_list(); - - DBUG_EXECUTE_IF("ib_undo_trunc_trunc_done", - ib::info() << "ib_undo_trunc_trunc_done"; - DBUG_SUICIDE();); } /********************************************************************//** diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index b48f3e18f1b..1c2d708ed4b 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2018, MariaDB Corporation. 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 @@ -86,7 +86,9 @@ trx_rseg_header_create( /* Reset the undo log slots */ for (i = 0; i < TRX_RSEG_N_SLOTS; i++) { - + /* FIXME: This is generating a lot of redo log. + Why not just let it remain zero-initialized, + and adjust trx_rsegf_undo_find_free() and friends? */ trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr); } diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc index c93003f9e03..2e069aa2937 100644 --- a/storage/innobase/trx/trx0undo.cc +++ b/storage/innobase/trx/trx0undo.cc @@ -1889,102 +1889,3 @@ trx_undo_free_prepared( undo = NULL; } } - -/** Truncate UNDO tablespace, reinitialize header and rseg. -@param[in] undo_trunc UNDO tablespace handler -@return true if success else false. */ -bool -trx_undo_truncate_tablespace( - undo::Truncate* undo_trunc) - -{ - bool success = true; - ulint space_id = undo_trunc->get_marked_space_id(); - - /* Step-1: Truncate tablespace. */ - success = fil_truncate_tablespace( - space_id, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES); - - if (!success) { - return(success); - } - - /* Step-2: Re-initialize tablespace header. - Avoid REDO logging as we don't want to apply the action if server - crashes. For fix-up we have UNDO-truncate-ddl-log. */ - mtr_t mtr; - mtr_start(&mtr); - mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); - fsp_header_init(space_id, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr); - mtr_commit(&mtr); - - /* Step-3: Re-initialize rollback segment header that resides - in truncated tablespaced. */ - mtr_start(&mtr); - mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); - mtr_x_lock(fil_space_get_latch(space_id, NULL), &mtr); - - for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) { - trx_rsegf_t* rseg_header; - - trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i); - - rseg->page_no = trx_rseg_header_create( - space_id, ULINT_MAX, rseg->id, &mtr); - - rseg_header = trx_rsegf_get_new(space_id, rseg->page_no, &mtr); - - /* Before re-initialization ensure that we free the existing - structure. There can't be any active transactions. */ - ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0); - ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0); - - trx_undo_t* next_undo; - - for (trx_undo_t* undo = - UT_LIST_GET_FIRST(rseg->update_undo_cached); - undo != NULL; - undo = next_undo) { - - next_undo = UT_LIST_GET_NEXT(undo_list, undo); - UT_LIST_REMOVE(rseg->update_undo_cached, undo); - MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED); - trx_undo_mem_free(undo); - } - - for (trx_undo_t* undo = - UT_LIST_GET_FIRST(rseg->insert_undo_cached); - undo != NULL; - undo = next_undo) { - - next_undo = UT_LIST_GET_NEXT(undo_list, undo); - UT_LIST_REMOVE(rseg->insert_undo_cached, undo); - MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED); - trx_undo_mem_free(undo); - } - - UT_LIST_INIT(rseg->update_undo_list, &trx_undo_t::undo_list); - UT_LIST_INIT(rseg->update_undo_cached, &trx_undo_t::undo_list); - UT_LIST_INIT(rseg->insert_undo_list, &trx_undo_t::undo_list); - UT_LIST_INIT(rseg->insert_undo_cached, &trx_undo_t::undo_list); - - rseg->max_size = mtr_read_ulint( - rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, &mtr); - - /* Initialize the undo log lists according to the rseg header */ - rseg->curr_size = mtr_read_ulint( - rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, &mtr) - + 1; - - ut_ad(rseg->curr_size == 1); - - rseg->trx_ref_count = 0; - rseg->last_page_no = FIL_NULL; - rseg->last_offset = 0; - rseg->last_trx_no = 0; - rseg->last_del_marks = FALSE; - } - mtr_commit(&mtr); - - return(success); -} diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index b4bfc152053..4c63e95a364 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -12859,13 +12859,22 @@ int ha_mroonga::delete_all_rows() int ha_mroonga::wrapper_truncate() { int error = 0; + MRN_SHARE *tmp_share; MRN_DBUG_ENTER_METHOD(); + + if (!(tmp_share = mrn_get_share(table->s->table_name.str, table, &error))) + DBUG_RETURN(error); + MRN_SET_WRAP_SHARE_KEY(share, table->s); MRN_SET_WRAP_TABLE_KEY(this, table); - error = wrap_handler->ha_truncate(); + error = parse_engine_table_options(ha_thd(), tmp_share->hton, table->s) + ? MRN_GET_ERROR_NUMBER + : wrap_handler->ha_truncate(); MRN_SET_BASE_SHARE_KEY(share, table->s); MRN_SET_BASE_TABLE_KEY(this, table); + mrn_free_share(tmp_share); + if (!error && wrapper_have_target_index()) { error = wrapper_truncate_index(); } From e67b1070bb0ca610c989af5d365bd342df511256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 28 Aug 2018 22:41:17 +0300 Subject: [PATCH 2/7] MDEV-17049 Enable innodb_undo tests on buildbot Remove the innodb_undo suite, and move and adapt the tests. Remove unnecessary restarts, and add innodb_page_size_small.inc for combinations. innodb.undo_truncate is the merge of innodb_undo.truncate and innodb_undo.truncate_multi_client. Add the global status variable innodb_undo_truncations. Without this, the test innodb.undo_truncate would occasionally report that truncation did not happen. The test was only waiting for the history list length to reach 0, but the undo tablespace truncation would only take place some time after that. Undo tablespace truncation will only occasionally occur with innodb_page_size=32k, and typically never occur (with this amount of undo log operations) with innodb_page_size=64k. We disable these combinations. innodb.undo_truncate_recover was formerly called innodb_undo.truncate_recover. --- .../have_undo_tablespaces.combinations | 0 .../include/have_undo_tablespaces.inc | 0 .../r/undo_truncate.result} | 19 ++- .../r/undo_truncate_recover.result} | 0 mysql-test/suite/innodb/t/undo_truncate.test | 128 ++++++++++++++++++ .../t/undo_truncate_recover.test} | 0 .../suite/innodb_undo/r/truncate.result | 12 -- mysql-test/suite/innodb_undo/t/truncate.test | 73 ---------- .../innodb_undo/t/truncate_multi_client.test | 78 ----------- storage/innobase/handler/ha_innodb.cc | 2 + storage/innobase/include/srv0srv.h | 2 + storage/innobase/trx/trx0purge.cc | 3 + 12 files changed, 149 insertions(+), 168 deletions(-) rename mysql-test/suite/{innodb_undo => innodb}/include/have_undo_tablespaces.combinations (100%) rename mysql-test/suite/{innodb_undo => innodb}/include/have_undo_tablespaces.inc (100%) rename mysql-test/suite/{innodb_undo/r/truncate_multi_client.result => innodb/r/undo_truncate.result} (60%) rename mysql-test/suite/{innodb_undo/r/truncate_recover.result => innodb/r/undo_truncate_recover.result} (100%) create mode 100644 mysql-test/suite/innodb/t/undo_truncate.test rename mysql-test/suite/{innodb_undo/t/truncate_recover.test => innodb/t/undo_truncate_recover.test} (100%) delete mode 100644 mysql-test/suite/innodb_undo/r/truncate.result delete mode 100644 mysql-test/suite/innodb_undo/t/truncate.test delete mode 100644 mysql-test/suite/innodb_undo/t/truncate_multi_client.test diff --git a/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations b/mysql-test/suite/innodb/include/have_undo_tablespaces.combinations similarity index 100% rename from mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations rename to mysql-test/suite/innodb/include/have_undo_tablespaces.combinations diff --git a/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.inc b/mysql-test/suite/innodb/include/have_undo_tablespaces.inc similarity index 100% rename from mysql-test/suite/innodb_undo/include/have_undo_tablespaces.inc rename to mysql-test/suite/innodb/include/have_undo_tablespaces.inc diff --git a/mysql-test/suite/innodb_undo/r/truncate_multi_client.result b/mysql-test/suite/innodb/r/undo_truncate.result similarity index 60% rename from mysql-test/suite/innodb_undo/r/truncate_multi_client.result rename to mysql-test/suite/innodb/r/undo_truncate.result index 0333a70d771..89171d36d0f 100644 --- a/mysql-test/suite/innodb_undo/r/truncate_multi_client.result +++ b/mysql-test/suite/innodb/r/undo_truncate.result @@ -1,5 +1,13 @@ call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; +SET @save_undo_logs = @@GLOBAL.innodb_undo_logs; +SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; +SET @save_truncate = @@GLOBAL.innodb_undo_log_truncate; +SET GLOBAL innodb_undo_log_truncate = 0; +SET GLOBAL innodb_undo_logs = 4; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; +SET @trunc_start= +(SELECT variable_value FROM information_schema.global_status +WHERE variable_name = 'innodb_undo_truncations'); create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; CREATE PROCEDURE populate_t1() @@ -37,6 +45,7 @@ delete from t1; connection con2; delete from t2; connection con1; +SET GLOBAL innodb_undo_log_truncate = 1; commit; disconnect con1; connection con2; @@ -46,7 +55,7 @@ connection default; drop table t1, t2; drop PROCEDURE populate_t1; drop PROCEDURE populate_t2; -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; -FOUND 1 /Truncating UNDO tablespace 1/ in mysqld.1.err +InnoDB 0 transactions not purged +SET GLOBAL innodb_undo_logs = @save_undo_logs; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; +SET GLOBAL innodb_undo_log_truncate = @save_truncate; diff --git a/mysql-test/suite/innodb_undo/r/truncate_recover.result b/mysql-test/suite/innodb/r/undo_truncate_recover.result similarity index 100% rename from mysql-test/suite/innodb_undo/r/truncate_recover.result rename to mysql-test/suite/innodb/r/undo_truncate_recover.result diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test new file mode 100644 index 00000000000..4f350e380ee --- /dev/null +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -0,0 +1,128 @@ +--source include/have_innodb.inc +# With 32k, truncation could happen on shutdown after the test, +# and the mtr.add_suppression() would not filter out the warning. +# With 64k, no truncation seems to happen. +# --source include/innodb_page_size.inc +--source include/innodb_page_size_small.inc +--source include/have_undo_tablespaces.inc + +call mtr.add_suppression("InnoDB: The transaction log size is too large"); + +SET @save_undo_logs = @@GLOBAL.innodb_undo_logs; +SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; +SET @save_truncate = @@GLOBAL.innodb_undo_log_truncate; +SET GLOBAL innodb_undo_log_truncate = 0; +SET GLOBAL innodb_undo_logs = 4; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; + +SET @trunc_start= +(SELECT variable_value FROM information_schema.global_status +WHERE variable_name = 'innodb_undo_truncations'); + +#----------------------------------------------------------------------------- +# +# Perform DML action using multiple clients and multiple undo tablespace. +# +# +create table t1(keyc int primary key, c char(100)) engine = innodb; +create table t2(keyc int primary key, c char(100)) engine = innodb; +# +delimiter |; +CREATE PROCEDURE populate_t1() +BEGIN + DECLARE i INT DEFAULT 1; + while (i <= 20000) DO + insert into t1 values (i, 'a'); + SET i = i + 1; + END WHILE; +END | +delimiter ;| +# +delimiter |; +CREATE PROCEDURE populate_t2() +BEGIN + DECLARE i INT DEFAULT 1; + while (i <= 20000) DO + insert into t2 values (i, 'a'); + SET i = i + 1; + END WHILE; +END | +delimiter ;| +# +# +let DATADIR = `select @@datadir`; +connect (con1,localhost,root,,); +begin; +send call populate_t1(); + +connect (con2,localhost,root,,); +begin; +send call populate_t2(); + +connection con1; reap; send update t1 set c = 'mysql'; +connection con2; reap; send update t2 set c = 'mysql'; +connection con1; reap; send update t1 set c = 'oracle'; +connection con2; reap; send update t2 set c = 'oracle'; +connection con1; reap; send delete from t1; +connection con2; reap; delete from t2; +connection con1; reap; + +let CHECKFILE = $MYSQL_TMP_DIR/check.txt; +perl; +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) + = stat("$ENV{DATADIR}/undo001"); +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) + = stat("$ENV{DATADIR}/undo002"); +open(OUT, ">$ENV{CHECKFILE}") || die; +print OUT "let \$size1='$size1,$size2';\n"; +close(OUT); +EOF + +SET GLOBAL innodb_undo_log_truncate = 1; +commit; disconnect con1; +connection con2; commit; disconnect con2; + +connection default; +drop table t1, t2; +drop PROCEDURE populate_t1; +drop PROCEDURE populate_t2; + +--source include/wait_all_purged.inc + +# Truncation will normally not occur with innodb_page_size=64k, +# and occasionally not with innodb_page_size=32k, +# because the undo log will not grow enough. +if (`select @@innodb_page_size IN (4096,8192,16384)`) +{ + let $wait_condition = (SELECT variable_value!=@trunc_start + FROM information_schema.global_status + WHERE variable_name = 'innodb_undo_truncations'); + source include/wait_condition.inc; +} + +--source $CHECKFILE +perl; +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) + = stat("$ENV{DATADIR}/undo001"); +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) + = stat("$ENV{DATADIR}/undo002"); +open(OUT, ">$ENV{CHECKFILE}") || die; +print OUT "let \$size2='$size1,$size2';\n"; +close(OUT); +EOF + +--source $CHECKFILE +--remove_file $CHECKFILE + +if ($size1 == $size2) +{ + # This fails for innodb_page_size=64k, occasionally also for 32k. + if (`select @@innodb_page_size IN (4096,8192,16384)`) + { + echo Truncation did not happen: $size1; + } +} + +SET GLOBAL innodb_undo_logs = @save_undo_logs; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; +SET GLOBAL innodb_undo_log_truncate = @save_truncate; diff --git a/mysql-test/suite/innodb_undo/t/truncate_recover.test b/mysql-test/suite/innodb/t/undo_truncate_recover.test similarity index 100% rename from mysql-test/suite/innodb_undo/t/truncate_recover.test rename to mysql-test/suite/innodb/t/undo_truncate_recover.test diff --git a/mysql-test/suite/innodb_undo/r/truncate.result b/mysql-test/suite/innodb_undo/r/truncate.result deleted file mode 100644 index 2194eed3e7b..00000000000 --- a/mysql-test/suite/innodb_undo/r/truncate.result +++ /dev/null @@ -1,12 +0,0 @@ -call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; -create table t1(keyc int primary key, c1 char(100)) engine = innodb; -begin; -update t1 set c1 = 'mysql'; -update t1 set c1 = 'oracle'; -delete from t1; -commit; -drop table t1; -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; diff --git a/mysql-test/suite/innodb_undo/t/truncate.test b/mysql-test/suite/innodb_undo/t/truncate.test deleted file mode 100644 index cc18434ae13..00000000000 --- a/mysql-test/suite/innodb_undo/t/truncate.test +++ /dev/null @@ -1,73 +0,0 @@ -# -# WL#6965: Truncate UNDO logs. -# - ---source include/have_innodb.inc ---source include/have_innodb_max_16k.inc ---source include/have_undo_tablespaces.inc - -# The test is restarting the server to force undo truncation. ---source include/not_embedded.inc - -call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; ---let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_undo_logs=4 ---source include/restart_mysqld.inc - -let MYSQLD_DATADIR = `select @@datadir`; - -#----------------------------------------------------------------------------- -# -# 1. Perform enough DML action so that undo tablespace size grows beyond -# set threshold and then wait and see if it is being truncated. -# -create table t1(keyc int primary key, c1 char(100)) engine = innodb; -begin; ---disable_query_log -let $i=30000; -while ($i) { - eval insert into t1 values(30000-$i, ''); - dec $i; -} ---enable_query_log -update t1 set c1 = 'mysql'; -update t1 set c1 = 'oracle'; -delete from t1; -commit; -drop table t1; - -let CHECKFILE = $MYSQL_TMP_DIR/check.txt; -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{MYSQLD_DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{MYSQLD_DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size1='$size1,$size2';\n"; -close(OUT); -EOF -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; ---source include/shutdown_mysqld.inc ---source $CHECKFILE -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{MYSQLD_DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{MYSQLD_DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size2='$size1,$size2';\n"; -close(OUT); -EOF - ---source $CHECKFILE ---remove_file $CHECKFILE - -if ($size1 == $size2) -{ - echo Truncation did not happen: $size1 == $size2; -} - ---let $restart_parameters= ---source include/start_mysqld.inc diff --git a/mysql-test/suite/innodb_undo/t/truncate_multi_client.test b/mysql-test/suite/innodb_undo/t/truncate_multi_client.test deleted file mode 100644 index 6a3d702d0d5..00000000000 --- a/mysql-test/suite/innodb_undo/t/truncate_multi_client.test +++ /dev/null @@ -1,78 +0,0 @@ -# -# WL#6965: Truncate UNDO logs. -# - ---source include/have_innodb.inc -# This test is restarting the server. ---source include/not_embedded.inc -# With larger innodb_page_size, the undo log tablespaces do not grow enough. ---source include/have_innodb_max_16k.inc ---source include/have_undo_tablespaces.inc - -call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; ---let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_undo_logs=4 ---source include/restart_mysqld.inc - -#----------------------------------------------------------------------------- -# -# Perform DML action using multiple clients and multiple undo tablespace. -# -# -create table t1(keyc int primary key, c char(100)) engine = innodb; -create table t2(keyc int primary key, c char(100)) engine = innodb; -# -delimiter |; -CREATE PROCEDURE populate_t1() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t1 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -delimiter |; -CREATE PROCEDURE populate_t2() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t2 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -# -connect (con1,localhost,root,,); -begin; -send call populate_t1(); - -connect (con2,localhost,root,,); -begin; -send call populate_t2(); - -connection con1; reap; send update t1 set c = 'mysql'; -connection con2; reap; send update t2 set c = 'mysql'; -connection con1; reap; send update t1 set c = 'oracle'; -connection con2; reap; send update t2 set c = 'oracle'; -connection con1; reap; send delete from t1; -connection con2; reap; send delete from t2; -connection con1; reap; commit; disconnect con1; -connection con2; reap; commit; disconnect con2; - -connection default; -drop table t1, t2; -drop PROCEDURE populate_t1; -drop PROCEDURE populate_t2; - -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; - ---source include/restart_mysqld.inc - -let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err; -let SEARCH_PATTERN = Truncating UNDO tablespace 1; ---source include/search_pattern_in_file.inc diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5d79c22edcf..6bbb4c3f81b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1100,6 +1100,8 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_truncated_status_writes, SHOW_LONG}, {"available_undo_logs", (char*) &export_vars.innodb_available_undo_logs, SHOW_LONG}, + {"undo_truncations", + (char*) &export_vars.innodb_undo_truncations, SHOW_LONG}, /* Status variables for page compression */ {"page_compression_saved", diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 7adfe295710..ecd2914515d 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -1022,6 +1022,8 @@ struct export_var_t{ ulint innodb_truncated_status_writes; /*!< srv_truncated_status_writes */ ulint innodb_available_undo_logs; /*!< srv_available_undo_logs */ + /** Number of undo tablespace truncation operations */ + ulong innodb_undo_truncations; ulint innodb_defragment_compression_failures; /*!< Number of defragment re-compression failures */ diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index c5f7b6c895b..6a88b335f17 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -1076,6 +1076,9 @@ trx_purge_initiate_truncate( os_file_truncate(file->name, file->handle, os_offset_t(size) << srv_page_size_shift, true); + /* This is only executed by the srv_coordinator_thread. */ + export_vars.innodb_undo_truncations++; + /* TODO: PUNCH_HOLE the garbage (with write-ahead logging) */ mutex_enter(&fil_system->mutex); From cf2a4426a2e864f35d002b1595fdffd4fe85ee4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 6 Sep 2018 10:32:49 +0300 Subject: [PATCH 3/7] MDEV-14717 RENAME TABLE in InnoDB is not crash-safe This is a backport of commit 0bc36758ba08ddeea6f7896a0fb815a13a48895a and commit 9eb3fcc9fbccfb13ad26e5d9faa0f70b580f291e. InnoDB in MariaDB 10.2 appears to only write MLOG_FILE_RENAME2 redo log records during table-rebuilding ALGORITHM=INPLACE operations. We must write the records for any .ibd file renames, so that the operations are crash-safe. If InnoDB is killed during a RENAME TABLE operation, it can happen that the transaction for updating the data dictionary will be rolled back. But, nothing will roll back the renaming of the .ibd file (the MLOG_FILE_RENAME2 only guarantees roll-forward), or for that matter, the renaming of the dict_table_t::name in the dict_sys cache. We introduce the undo log record TRX_UNDO_RENAME_TABLE to fix this. fil_space_for_table_exists_in_mem(): Remove the parameters adjust_space, table_id and some code that was trying to work around these deficiencies. fil_name_write_rename(): Write a MLOG_FILE_RENAME2 record. dict_table_rename_in_cache(): Invoke fil_name_write_rename(). trx_undo_rec_copy(): Set the first 2 bytes to the length of the copied undo log record. trx_undo_page_report_rename(), trx_undo_report_rename(): Write a TRX_UNDO_RENAME_TABLE record with the old table name. row_rename_table_for_mysql(): Invoke trx_undo_report_rename() before modifying any data dictionary tables. row_undo_ins_parse_undo_rec(): Roll back TRX_UNDO_RENAME_TABLE by invoking dict_table_rename_in_cache(), which will take care of both renaming the table and the file. ha_innobase::truncate(): Remove a work-around. --- .../suite/innodb/r/rename_table_debug.result | 12 ++ .../suite/innodb/t/rename_table_debug.test | 19 +++ storage/innobase/dict/dict0dict.cc | 2 + storage/innobase/dict/dict0load.cc | 5 +- storage/innobase/fil/fil0fil.cc | 69 ++++------- storage/innobase/handler/ha_innodb.cc | 8 +- storage/innobase/include/dict0dict.h | 2 +- storage/innobase/include/fil0fil.h | 40 ++++--- storage/innobase/include/trx0rec.h | 8 ++ storage/innobase/include/trx0rec.ic | 5 +- storage/innobase/row/row0mysql.cc | 16 ++- storage/innobase/row/row0uins.cc | 26 +++- storage/innobase/trx/trx0rec.cc | 113 ++++++++++++++++++ storage/innobase/trx/trx0roll.cc | 10 +- 14 files changed, 249 insertions(+), 86 deletions(-) create mode 100644 mysql-test/suite/innodb/r/rename_table_debug.result create mode 100644 mysql-test/suite/innodb/t/rename_table_debug.test diff --git a/mysql-test/suite/innodb/r/rename_table_debug.result b/mysql-test/suite/innodb/r/rename_table_debug.result new file mode 100644 index 00000000000..912ed9de48b --- /dev/null +++ b/mysql-test/suite/innodb/r/rename_table_debug.result @@ -0,0 +1,12 @@ +CREATE TABLE t1 (a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES(42); +connect con1,localhost,root,,test; +SET DEBUG_SYNC='before_rename_table_commit SIGNAL renamed WAIT_FOR ever'; +RENAME TABLE t1 TO t2; +connection default; +SET DEBUG_SYNC='now WAIT_FOR renamed'; +disconnect con1; +SELECT * FROM t1; +a +42 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/rename_table_debug.test b/mysql-test/suite/innodb/t/rename_table_debug.test new file mode 100644 index 00000000000..4620f7bef22 --- /dev/null +++ b/mysql-test/suite/innodb/t/rename_table_debug.test @@ -0,0 +1,19 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/not_embedded.inc + +CREATE TABLE t1 (a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES(42); + +--connect (con1,localhost,root,,test) +SET DEBUG_SYNC='before_rename_table_commit SIGNAL renamed WAIT_FOR ever'; +--send +RENAME TABLE t1 TO t2; +--connection default +SET DEBUG_SYNC='now WAIT_FOR renamed'; +--let $shutdown_timeout=0 +--source include/restart_mysqld.inc +--disconnect con1 +SELECT * FROM t1; +DROP TABLE t1; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index eb31afe2947..8f23bb4a54f 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1692,6 +1692,8 @@ dict_table_rename_in_cache( return(err); } + fil_name_write_rename(table->space, old_path, new_path); + bool success = fil_rename_tablespace( table->space, old_path, new_name, new_path); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 022535631cc..77415d30643 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -1448,7 +1448,7 @@ dict_check_sys_tables( look to see if it is already in the tablespace cache. */ if (fil_space_for_table_exists_in_mem( space_id, table_name.m_name, - false, true, NULL, 0, flags)) { + false, NULL, flags)) { /* Recovery can open a datafile that does not match SYS_DATAFILES. If they don't match, update SYS_DATAFILES. */ @@ -2857,8 +2857,7 @@ dict_load_tablespace( /* The tablespace may already be open. */ if (fil_space_for_table_exists_in_mem( - table->space, space_name, false, - true, heap, table->id, table->flags)) { + table->space, space_name, false, heap, table->flags)) { return; } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 386493eef18..d42402b322d 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -2313,7 +2313,7 @@ fil_op_write_log( @param[in,out] mtr mini-transaction */ static void -fil_name_write_rename( +fil_name_write_rename_low( ulint space_id, ulint first_page_no, const char* old_name, @@ -2327,6 +2327,23 @@ fil_name_write_rename( space_id, first_page_no, old_name, new_name, 0, mtr); } +/** Write redo log for renaming a file. +@param[in] space_id tablespace id +@param[in] old_name tablespace file name +@param[in] new_name tablespace file name after renaming */ +void +fil_name_write_rename( + ulint space_id, + const char* old_name, + const char* new_name) +{ + mtr_t mtr; + mtr.start(); + fil_name_write_rename_low(space_id, 0, old_name, new_name, &mtr); + mtr.commit(); + log_write_up_to(mtr.commit_lsn(), true); +} + /** Write MLOG_FILE_NAME for a file. @param[in] space_id tablespace id @param[in] first_page_no first page number in the file @@ -3394,12 +3411,7 @@ func_exit: ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != NULL); if (!recv_recovery_on) { - mtr_t mtr; - - mtr.start(); - fil_name_write_rename( - id, 0, old_file_name, new_file_name, &mtr); - mtr.commit(); + fil_name_write_rename(id, old_file_name, new_file_name); log_mutex_enter(); } @@ -4457,9 +4469,7 @@ startup, there may be many tablespaces which are not yet in the memory cache. @param[in] print_error_if_does_not_exist Print detailed error information to the error log if a matching tablespace is not found from memory. -@param[in] adjust_space Whether to adjust space id on mismatch @param[in] heap Heap memory -@param[in] table_id table id @param[in] table_flags table flags @return true if a matching tablespace exists in the memory cache */ bool @@ -4467,9 +4477,7 @@ fil_space_for_table_exists_in_mem( ulint id, const char* name, bool print_error_if_does_not_exist, - bool adjust_space, mem_heap_t* heap, - table_id_t table_id, ulint table_flags) { fil_space_t* fnamespace; @@ -4494,41 +4502,6 @@ fil_space_for_table_exists_in_mem( } else if (!valid || space == fnamespace) { /* Found with the same file name, or got a flag mismatch. */ goto func_exit; - } else if (adjust_space - && row_is_mysql_tmp_table_name(space->name) - && !row_is_mysql_tmp_table_name(name)) { - /* Info from fnamespace comes from the ibd file - itself, it can be different from data obtained from - System tables since renaming files is not - transactional. We shall adjust the ibd file name - according to system table info. */ - mutex_exit(&fil_system->mutex); - - DBUG_EXECUTE_IF("ib_crash_before_adjust_fil_space", - DBUG_SUICIDE();); - - const char* tmp_name = dict_mem_create_temporary_tablename( - heap, name, table_id); - - fil_rename_tablespace( - fnamespace->id, - UT_LIST_GET_FIRST(fnamespace->chain)->name, - tmp_name, NULL); - - DBUG_EXECUTE_IF("ib_crash_after_adjust_one_fil_space", - DBUG_SUICIDE();); - - fil_rename_tablespace( - id, UT_LIST_GET_FIRST(space->chain)->name, - name, NULL); - - DBUG_EXECUTE_IF("ib_crash_after_adjust_fil_space", - DBUG_SUICIDE();); - - mutex_enter(&fil_system->mutex); - fnamespace = fil_space_get_by_name(name); - ut_ad(space == fnamespace); - goto func_exit; } if (!print_error_if_does_not_exist) { @@ -5576,7 +5549,7 @@ fil_mtr_rename_log( return(err); } - fil_name_write_rename( + fil_name_write_rename_low( old_table->space, 0, old_path, tmp_path, mtr); ut_free(tmp_path); @@ -5607,7 +5580,7 @@ fil_mtr_rename_log( } } - fil_name_write_rename( + fil_name_write_rename_low( new_table->space, 0, new_path, old_path, mtr); ut_free(new_path); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 6bbb4c3f81b..0fdfaa449fd 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13353,6 +13353,7 @@ innobase_rename_table( DEBUG_SYNC_C("innodb_rename_table_ready"); trx_start_if_not_started(trx, true); + ut_ad(trx->will_lock > 0); /* Serialize data dictionary operations with dictionary mutex: no deadlocks can occur then in these operations. */ @@ -13504,13 +13505,6 @@ int ha_innobase::truncate() } if (err) { - /* Before MDEV-14717, rollback of RENAME TABLE fails - to undo the rename in the file system, so we do it - manually here. In case the server is killed before the - TRUNCATE operation is committed, after recovery in - MariaDB 10.2, the data file could end up "missing" - (remain called temp_name). */ - innobase_rename_table(trx, temp_name, name); trx_rollback_to_savepoint(trx, NULL); } diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index de997f0f684..b5f2b108959 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -411,7 +411,7 @@ dict_table_rename_in_cache( /*!< in: in ALTER TABLE we want to preserve the original table name in constraints which reference it */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); + MY_ATTRIBUTE((nonnull)); /** Removes an index from the dictionary cache. @param[in,out] table table whose index to remove diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index b2ee24c969b..1307598971b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -869,6 +869,15 @@ fil_create_directory_for_tablename( /*===============================*/ const char* name); /*!< in: name in the standard 'databasename/tablename' format */ +/** Write redo log for renaming a file. +@param[in] space_id tablespace id +@param[in] old_name tablespace file name +@param[in] new_name tablespace file name after renaming */ +void +fil_name_write_rename( + ulint space_id, + const char* old_name, + const char* new_name); /********************************************************//** Recreates table indexes by applying TRUNCATE log record during recovery. @@ -1128,27 +1137,24 @@ fil_file_readdir_next_file( os_file_dir_t dir, /*!< in: directory stream */ os_file_stat_t* info); /*!< in/out: buffer where the info is returned */ -/*******************************************************************//** -Returns true if a matching tablespace exists in the InnoDB tablespace memory -cache. Note that if we have not done a crash recovery at the database startup, -there may be many tablespaces which are not yet in the memory cache. +/** Determine if a matching tablespace exists in the InnoDB tablespace +memory cache. Note that if we have not done a crash recovery at the database +startup, there may be many tablespaces which are not yet in the memory cache. +@param[in] id Tablespace ID +@param[in] name Tablespace name used in fil_space_create(). +@param[in] print_error_if_does_not_exist + Print detailed error information to the +error log if a matching tablespace is not found from memory. +@param[in] heap Heap memory +@param[in] table_flags table flags @return true if a matching tablespace exists in the memory cache */ bool fil_space_for_table_exists_in_mem( -/*==============================*/ - ulint id, /*!< in: space id */ - const char* name, /*!< in: table name in the standard - 'databasename/tablename' format */ + ulint id, + const char* name, bool print_error_if_does_not_exist, - /*!< in: print detailed error - information to the .err log if a - matching tablespace is not found from - memory */ - bool adjust_space, /*!< in: whether to adjust space id - when find table space mismatch */ - mem_heap_t* heap, /*!< in: heap memory */ - table_id_t table_id, /*!< in: table id */ - ulint table_flags); /*!< in: table flags */ + mem_heap_t* heap, + ulint table_flags); /** Try to extend a tablespace if it is smaller than the specified size. @param[in,out] space tablespace diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h index be859fa9450..2551d5759ae 100644 --- a/storage/innobase/include/trx0rec.h +++ b/storage/innobase/include/trx0rec.h @@ -179,6 +179,13 @@ trx_undo_rec_get_partial_row( mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ MY_ATTRIBUTE((nonnull, warn_unused_result)); +/** Report a RENAME TABLE operation. +@param[in,out] trx transaction +@param[in] table table that is being renamed +@return DB_SUCCESS or error code */ +dberr_t +trx_undo_report_rename(trx_t* trx, const dict_table_t* table) + MY_ATTRIBUTE((nonnull, warn_unused_result)); /***********************************************************************//** Writes information to an undo log about an insert, update, or a delete marking of a clustered index record. This information is used in a rollback of the @@ -322,6 +329,7 @@ trx_undo_read_v_idx( compilation info multiplied by 16 is ORed to this value in an undo log record */ +#define TRX_UNDO_RENAME_TABLE 9 /*!< RENAME TABLE */ #define TRX_UNDO_INSERT_REC 11 /* fresh insert into clustered index */ #define TRX_UNDO_UPD_EXIST_REC 12 /* update of a non-delete-marked record */ diff --git a/storage/innobase/include/trx0rec.ic b/storage/innobase/include/trx0rec.ic index c2c756484b2..d0771a94b05 100644 --- a/storage/innobase/include/trx0rec.ic +++ b/storage/innobase/include/trx0rec.ic @@ -95,5 +95,8 @@ trx_undo_rec_copy( len = mach_read_from_2(undo_rec) - ut_align_offset(undo_rec, UNIV_PAGE_SIZE); ut_ad(len < UNIV_PAGE_SIZE); - return((trx_undo_rec_t*) mem_heap_dup(heap, undo_rec, len)); + trx_undo_rec_t* rec = static_cast( + mem_heap_dup(heap, undo_rec, len)); + mach_write_to_2(rec, len); + return rec; } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 97c04546ee7..4677dfc296a 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3299,7 +3299,7 @@ row_drop_single_table_tablespace( /* If the tablespace is not in the cache, just delete the file. */ if (!fil_space_for_table_exists_in_mem( - space_id, tablename, true, false, NULL, 0, table_flags)) { + space_id, tablename, true, NULL, table_flags)) { /* Force a delete of any discarded or temporary files. */ fil_delete_file(filepath); @@ -4391,6 +4391,14 @@ row_rename_table_for_mysql( goto funct_exit; } + if (!table->is_temporary()) { + err = trx_undo_report_rename(trx, table); + + if (err != DB_SUCCESS) { + goto funct_exit; + } + } + /* We use the private SQL parser of Innobase to generate the query graphs needed in updating the dictionary data from system tables. */ @@ -4576,8 +4584,9 @@ row_rename_table_for_mysql( } } - if ((dict_table_has_fts_index(table) - || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) + if (err == DB_SUCCESS + && (dict_table_has_fts_index(table) + || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) && !dict_tables_have_same_db(old_name, new_name)) { err = fts_rename_aux_tables(table, new_name, trx); if (err != DB_TABLE_NOT_FOUND) { @@ -4734,6 +4743,7 @@ funct_exit: } if (commit) { + DEBUG_SYNC(trx->mysql_thd, "before_rename_table_commit"); trx_commit_for_mysql(trx); } diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 2e0ef551442..9b4a062b00f 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -330,16 +330,13 @@ row_undo_ins_parse_undo_rec( byte* ptr; undo_no_t undo_no; table_id_t table_id; - ulint type; ulint dummy; bool dummy_extern; ut_ad(node); - ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &dummy, + ptr = trx_undo_rec_get_pars(node->undo_rec, &node->rec_type, &dummy, &dummy_extern, &undo_no, &table_id); - ut_ad(type == TRX_UNDO_INSERT_REC); - node->rec_type = type; node->update = NULL; node->table = dict_table_open_on_id( @@ -350,6 +347,27 @@ row_undo_ins_parse_undo_rec( return; } + switch (node->rec_type) { + default: + ut_ad(!"wrong undo record type"); + goto close_table; + case TRX_UNDO_INSERT_REC: + break; + case TRX_UNDO_RENAME_TABLE: + dict_table_t* table = node->table; + ut_ad(!table->is_temporary()); + ut_ad(dict_table_is_file_per_table(table) + == (table->space != TRX_SYS_SPACE)); + size_t len = mach_read_from_2(node->undo_rec) + + node->undo_rec - ptr - 2; + ptr[len] = 0; + const char* name = reinterpret_cast(ptr); + if (strcmp(table->name.m_name, name)) { + dict_table_rename_in_cache(table, name, false); + } + goto close_table; + } + if (UNIV_UNLIKELY(!fil_table_accessible(node->table))) { close_table: /* Normally, tables should not disappear or become diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 1851f30339b..1c55106f016 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1880,6 +1880,119 @@ trx_undo_parse_erase_page_end( return(ptr); } +/** Report a RENAME TABLE operation. +@param[in,out] trx transaction +@param[in] table table that is being renamed +@param[in,out] block undo page +@param[in,out] mtr mini-transaction +@return byte offset of the undo log record +@retval 0 in case of failure */ +static +ulint +trx_undo_page_report_rename(trx_t* trx, const dict_table_t* table, + buf_block_t* block, mtr_t* mtr) +{ + byte* ptr_first_free = TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_FREE + + block->frame; + ulint first_free = mach_read_from_2(ptr_first_free); + ut_ad(first_free >= TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE); + ut_ad(first_free <= UNIV_PAGE_SIZE); + byte* start = block->frame + first_free; + size_t len = strlen(table->name.m_name); + const size_t fixed = 2 + 1 + 11 + 11 + 2; + ut_ad(len <= NAME_LEN * 2 + 1); + /* The -10 is used in trx_undo_left() */ + compile_time_assert((NAME_LEN * 1) * 2 + fixed + + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE + < UNIV_PAGE_SIZE_MIN - 10 - FIL_PAGE_DATA_END); + + if (trx_undo_left(block->frame, start) < fixed + len) { + ut_ad(first_free > TRX_UNDO_PAGE_HDR + + TRX_UNDO_PAGE_HDR_SIZE); + return 0; + } + + byte* ptr = start + 2; + *ptr++ = TRX_UNDO_RENAME_TABLE; + ptr += mach_u64_write_much_compressed(ptr, trx->undo_no); + ptr += mach_u64_write_much_compressed(ptr, table->id); + memcpy(ptr, table->name.m_name, len); + ptr += len; + mach_write_to_2(ptr, first_free); + ptr += 2; + ulint offset = page_offset(ptr); + mach_write_to_2(start, offset); + mach_write_to_2(ptr_first_free, offset); + + trx_undof_page_add_undo_rec_log(block->frame, first_free, offset, mtr); + return first_free; +} + +/** Report a RENAME TABLE operation. +@param[in,out] trx transaction +@param[in] table table that is being renamed +@return DB_SUCCESS or error code */ +dberr_t +trx_undo_report_rename(trx_t* trx, const dict_table_t* table) +{ + ut_ad(!trx->read_only); + ut_ad(trx->id); + ut_ad(!table->is_temporary()); + + trx_rseg_t* rseg = trx->rsegs.m_redo.rseg; + trx_undo_t** pundo = &trx->rsegs.m_redo.insert_undo; + mutex_enter(&trx->undo_mutex); + dberr_t err = *pundo + ? DB_SUCCESS + : trx_undo_assign_undo(trx, rseg, pundo, TRX_UNDO_INSERT); + ut_ad((err == DB_SUCCESS) == (*pundo != NULL)); + if (trx_undo_t* undo = *pundo) { + mtr_t mtr; + mtr.start(trx); + + buf_block_t* block = buf_page_get_gen( + page_id_t(undo->space, undo->last_page_no), + univ_page_size, RW_X_LATCH, + buf_pool_is_obsolete(undo->withdraw_clock) + ? NULL : undo->guess_block, + BUF_GET, __FILE__, __LINE__, &mtr, &err); + ut_ad((err == DB_SUCCESS) == !!block); + + for (ut_d(int loop_count = 0); block;) { + ut_ad(++loop_count < 2); + buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE); + ut_ad(undo->last_page_no == block->page.id.page_no()); + + if (ulint offset = trx_undo_page_report_rename( + trx, table, block, &mtr)) { + undo->withdraw_clock = buf_withdraw_clock; + undo->empty = FALSE; + undo->top_page_no = undo->last_page_no; + undo->top_offset = offset; + undo->top_undo_no = trx->undo_no++; + undo->guess_block = block; + + trx->undo_rseg_space = rseg->space; + err = DB_SUCCESS; + break; + } else { + mtr.commit(); + mtr.start(trx); + block = trx_undo_add_page(trx, undo, &mtr); + if (!block) { + err = DB_OUT_OF_FILE_SPACE; + break; + } + } + } + + mtr.commit(); + } + + mutex_exit(&trx->undo_mutex); + return err; +} + /***********************************************************************//** Writes information to an undo log about an insert, update, or a delete marking of a clustered index record. This information is used in a rollback of the diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index 82592fd3ae4..2c14c9d895a 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -1058,11 +1058,17 @@ trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap) trx_undo_rec_t* undo_rec = trx_roll_pop_top_rec(trx, undo, &mtr); const undo_no_t undo_no = trx_undo_rec_get_undo_no(undo_rec); - if (trx_undo_rec_get_type(undo_rec) == TRX_UNDO_INSERT_REC) { + switch (trx_undo_rec_get_type(undo_rec)) { + case TRX_UNDO_RENAME_TABLE: + ut_ad(undo == insert); + /* fall through */ + case TRX_UNDO_INSERT_REC: ut_ad(undo == insert || undo == temp); *roll_ptr |= 1ULL << ROLL_PTR_INSERT_FLAG_POS; - } else { + break; + default: ut_ad(undo == update || undo == temp); + break; } ut_ad(trx_roll_check_undo_rec_ordering( From 754727bb8a4a1850666ef024d5caad04512822db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 6 Sep 2018 11:40:27 +0300 Subject: [PATCH 4/7] MDEV-14378 In ALGORITHM=INPLACE, use a common name for the intermediate tables or partitions This is a backport of commit 07e9ff1fe18999e1acd640ee3b2169c3f506fb35. Allow DROP TABLE `#mysql50##sql-...._.` to drop tables that were being rebuilt by ALGORITHM=INPLACE NOTE: If the server is killed after the table-rebuilding ALGORITHM=INPLACE commits inside InnoDB but before the .frm file has been replaced, then the recovery will involve something else than DROP TABLE. NOTE: If the server is killed in a true inplace ALTER TABLE commits inside InnoDB but before the .frm file has been replaced, then we are really out of luck. To properly handle that situation, we would need a transactional mysql.ddl_fixup table that directs recovery to rename or remove files. prepare_inplace_alter_table_dict(): Use the altered_table->s->table_name for generating the new_table_name. table_name_t::part_suffix: The start of the partition name suffix. table_name_t::dbend(): Return the end of the schema name. table_name_t::dblen(): Return the length of the schema name, in bytes. table_name_t::basename(): Return the name without the schema name. table_name_t::part(): Return the partition name, or NULL if none. row_drop_table_for_mysql(): Assert for #sql, not #sql-ib. --- .../innodb/r/innodb-alter-tempfile.result | 16 +------ mysql-test/suite/innodb/t/alter_crash.test | 16 ++++--- .../suite/innodb/t/innodb-alter-tempfile.test | 47 ++++++------------- storage/innobase/dict/dict0mem.cc | 8 ++++ storage/innobase/handler/ha_innodb.cc | 6 +-- storage/innobase/handler/handler0alter.cc | 17 +++++-- storage/innobase/include/dict0mem.h | 23 +++++++++ storage/innobase/row/row0mysql.cc | 3 +- 8 files changed, 69 insertions(+), 67 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result index ce13ad0978b..b164c3c26b0 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result +++ b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result @@ -4,17 +4,10 @@ # Temporary tablename will be unique. This makes sure that future # in-place ALTERs of the same table will not be blocked due to # temporary tablename. -# Crash the server in ha_innobase::commit_inplace_alter_table() CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb; -SET debug='d,innodb_alter_commit_crash_before_commit'; -Warnings: -Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead -# Write file to make mysql-test-run.pl expect crash -# Execute the statement that causes the crash +SET debug_dbug='+d,innodb_alter_commit_crash_before_commit'; ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ERROR HY000: Lost connection to MySQL server during query -# Startup the server after the crash -# Read and remember the temporary table name show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -23,13 +16,6 @@ t1 CREATE TABLE `t1` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 # Consecutive Alter table does not create same temporary file name ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); -# Shutdown the server to allow manual recovery -# Manual recovery begin. The dictionary was not updated -# and the files were not renamed. The rebuilt table -# was left behind on purpose, to faciliate data recovery. -# Manual recovery end -# Startup the server after manual recovery -# Drop the orphaned rebuilt table. show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/suite/innodb/t/alter_crash.test b/mysql-test/suite/innodb/t/alter_crash.test index 54cc51aecf4..b4fdfd2f2d5 100644 --- a/mysql-test/suite/innodb/t/alter_crash.test +++ b/mysql-test/suite/innodb/t/alter_crash.test @@ -138,24 +138,27 @@ ALTER TABLE t2 ADD PRIMARY KEY (f2, f1); let $temp_table_name = `SELECT SUBSTRING(name,6) FROM information_schema.innodb_sys_tables WHERE name LIKE "test/#sql-ib$orig_table_id%"`; -# This second copy is an environment variable for the perl script below. -let temp_table_name = $temp_table_name; --echo # Manual *.frm recovery begin. The dictionary was not updated --echo # and the files were not renamed. The rebuilt table --echo # was left behind on purpose, to faciliate data recovery. +let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; perl; -my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm"; -my $target_frm = "$ENV{'datadir'}/test/$ENV{'temp_table_name'}.frm"; -rename($frm_file[0], $target_frm); +die unless open OUT, ">$ENV{TABLENAME_INC}"; +chdir "$ENV{'datadir'}/test"; +my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; +print OUT 'let $tablename=', $frm_file[0], ';'; +close OUT or die; EOF +source $TABLENAME_INC; +remove_file $TABLENAME_INC; --echo # Manual recovery end --echo # Drop the orphaned rebuilt table. --disable_query_log -eval DROP TABLE `#mysql50#$temp_table_name`; +eval DROP TABLE `#mysql50#$tablename`; --enable_query_log SHOW TABLES; @@ -186,7 +189,6 @@ SET DEBUG_DBUG='+d,innodb_alter_commit_crash_after_commit'; let $orig_table_id = `select table_id from information_schema.innodb_sys_tables where name = 'test/t1'`; -# FIXME: MDEV-9469 'Incorrect key file' on ALTER TABLE # Write file to make mysql-test-run.pl expect crash --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect # diff --git a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test index d3f34b12ea6..f2038da8c4c 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test +++ b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test @@ -24,49 +24,30 @@ let datadir= `select @@datadir`; --let $_server_id= `SELECT @@server_id` --let $_expect_file_name=$MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect ---echo # Crash the server in ha_innobase::commit_inplace_alter_table() CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb; -SET debug='d,innodb_alter_commit_crash_before_commit'; +SET debug_dbug='+d,innodb_alter_commit_crash_before_commit'; -let $orig_table_id = `SELECT table_id - FROM information_schema.innodb_sys_tables - WHERE name = 'test/t1'`; +--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect ---echo # Write file to make mysql-test-run.pl expect crash ---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect - ---echo # Execute the statement that causes the crash --error 2013 ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ---echo # Startup the server after the crash + +let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; +perl; +die unless open OUT, ">$ENV{TABLENAME_INC}"; +chdir "$ENV{'datadir'}/test"; +my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; +print OUT 'let $temp_table_name=', $frm_file[0], ';'; +close OUT or die; +EOF +source $TABLENAME_INC; +remove_file $TABLENAME_INC; + --source include/start_mysqld.inc ---echo # Read and remember the temporary table name -let $temp_table_name = `SELECT SUBSTRING(name,6) - FROM information_schema.innodb_sys_tables - WHERE name LIKE "test/#sql-ib$orig_table_id%"`; -# This second copy is an environment variable for the perl script below. -let temp_table_name = $temp_table_name; show create table t1; --echo # Consecutive Alter table does not create same temporary file name ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ---echo # Shutdown the server to allow manual recovery ---source include/shutdown_mysqld.inc - ---echo # Manual recovery begin. The dictionary was not updated ---echo # and the files were not renamed. The rebuilt table ---echo # was left behind on purpose, to faciliate data recovery. - -perl; -my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm"; -my $target_frm = "$ENV{'datadir'}/test/$ENV{'temp_table_name'}.frm"; -rename($frm_file[0], $target_frm); -EOF ---echo # Manual recovery end ---echo # Startup the server after manual recovery ---source include/start_mysqld.inc - ---echo # Drop the orphaned rebuilt table. --disable_query_log eval DROP TABLE `#mysql50#$temp_table_name`; --enable_query_log diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index dcf52c93de1..bde8303ead5 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -50,6 +50,14 @@ static const char* innobase_system_databases[] = { NullS }; +/** The start of the table basename suffix for partitioned tables */ +const char table_name_t::part_suffix[4] +#ifdef _WIN32 += "#p#"; +#else += "#P#"; +#endif + /** An interger randomly initialized at startup used to make a temporary table name as unuique as possible. */ static ib_uint32_t dict_temp_file_num; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0fdfaa449fd..7bb84b41a11 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -294,11 +294,7 @@ is_partition( { /* We look for pattern #P# to see if the table is partitioned MariaDB table. */ -#ifdef _WIN32 - return strstr(file_name, "#p#"); -#else - return strstr(file_name, "#P#"); -#endif /* _WIN32 */ + return strstr(file_name, table_name_t::part_suffix); } /** Signal to shut down InnoDB (NULL if shutdown was signaled, or if diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 8565cad96ec..412438237fa 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -4520,11 +4520,18 @@ prepare_inplace_alter_table_dict( to rebuild the table with a temporary name. */ if (new_clustered) { - const char* new_table_name - = dict_mem_create_temporary_tablename( - ctx->heap, - ctx->new_table->name.m_name, - ctx->new_table->id); + size_t dblen = ctx->old_table->name.dblen() + 1; + size_t tablen = altered_table->s->table_name.length; + const char* part = ctx->old_table->name.part(); + size_t partlen = part ? strlen(part) : 0; + char* new_table_name = static_cast( + mem_heap_alloc(ctx->heap, + dblen + tablen + partlen + 1)); + memcpy(new_table_name, ctx->old_table->name.m_name, dblen); + memcpy(new_table_name + dblen, + altered_table->s->table_name.str, tablen); + memcpy(new_table_name + dblen + tablen, + part ? part : "", partlen + 1); ulint n_cols = 0; ulint n_v_cols = 0; dtuple_t* add_cols; diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 44d1a11ab33..fc120149c5f 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -568,6 +568,29 @@ struct table_name_t { /** The name in internal representation */ char* m_name; + + /** @return the end of the schema name */ + const char* dbend() const + { + const char* sep = strchr(m_name, '/'); + ut_ad(sep); + return sep; + } + + /** @return the length of the schema name, in bytes */ + size_t dblen() const { return dbend() - m_name; } + + /** Determine the filename-safe encoded table name. + @return the filename-safe encoded table name */ + const char* basename() const { return dbend() + 1; } + + /** The start of the table basename suffix for partitioned tables */ + static const char part_suffix[4]; + + /** Determine the partition or subpartition name suffix. + @return the partition name + @retval NULL if the table is not partitioned */ + const char* part() const { return strstr(basename(), part_suffix); } }; /** Data structure for a column in a table */ diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 4677dfc296a..58d90cfb2ac 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3629,8 +3629,7 @@ row_drop_table_for_mysql( TRX_DICT_OP_INDEX, we should be dropping auxiliary tables for full-text indexes or temp tables. */ ut_ad(strstr(table->name.m_name, "/FTS_") - || strstr(table->name.m_name, - "/" TEMP_FILE_PREFIX_INNODB)); + || strstr(table->name.m_name, TEMP_TABLE_PATH_PREFIX)); } /* Mark all indexes unavailable in the data dictionary cache From 8dcacd3b01943746badd26265c5cff6d4d33a121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 6 Sep 2018 11:47:54 +0300 Subject: [PATCH 5/7] Follow-up to MDEV-13407 innodb.drop_table_background failed in buildbot with "Tablespace for table exists" This is a backport of commit 88aff5f471d3d9ae8ecc2f909bcf5bd0ddd6aa7c. The InnoDB background DROP TABLE queue is something that we should really remove, but are unable to until we remove dict_operation_lock so that DDL and DML operations can be combined in a single transaction. Because the queue is not persistent, it is not crash-safe. We should in some way ensure that the deferred-dropped tables will be dropped after server restart. The existence of two separate transactions complicates the error handling of CREATE TABLE...SELECT. We should really not break locks in DROP TABLE. Our solution to these problems is to rename the table to a temporary name, and to drop such-named tables on InnoDB startup. Also, the queue will use table IDs instead of names from now on. check-testcase.test: Ignore #sql-ib*.ibd files, because tables may enter the background DROP TABLE queue shortly before the test finishes. innodb.drop_table_background: Test CREATE...SELECT and the creation of tables whose file name starts with #sql-ib. innodb.alter_crash: Adjust the recovery, now that the #sql-ib tables will be dropped on InnoDB startup. row_mysql_drop_garbage_tables(): New function, to drop all #sql-ib tables on InnoDB startup. row_drop_table_for_mysql_in_background(): Remove an unnecessary and misplaced call to log_buffer_flush_to_disk(). (The call should have been after the transaction commit. We do not care about flushing the redo log here, because the table would be dropped again at server startup.) Remove the entry from the list after the table no longer exists. If server shutdown has been initiated, empty the list without actually dropping any tables. They will be dropped again on startup. row_drop_table_for_mysql(): Do not call lock_remove_all_on_table(). Instead, if locks exist, defer the DROP TABLE until they do not exist. If the table name does not start with #sql-ib, rename it to that prefix before adding it to the background DROP TABLE queue. --- mysql-test/include/check-testcase.test | 5 +- mysql-test/suite/innodb/r/alter_crash.result | 21 ++- .../innodb/r/drop_table_background.result | 15 ++ mysql-test/suite/innodb/t/alter_crash.test | 68 +++----- .../suite/innodb/t/drop_table_background.test | 14 ++ storage/innobase/include/row0mysql.h | 4 + storage/innobase/log/log0recv.cc | 2 + storage/innobase/row/row0mysql.cc | 146 ++++++++++++------ 8 files changed, 168 insertions(+), 107 deletions(-) diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test index a282201857e..4ca53989d06 100644 --- a/mysql-test/include/check-testcase.test +++ b/mysql-test/include/check-testcase.test @@ -82,7 +82,10 @@ call mtr.check_testcase(); let $datadir=`select @@datadir`; list_files $datadir mysql_upgrade_info; -list_files $datadir/test #sql*; +list_files_write_file $datadir.tempfiles.txt $datadir/test #sql*; +--replace_regex /#sql-ib[0-9a-f]+-[0-9a-f]+\.ibd\n// +cat_file $datadir.tempfiles.txt; +remove_file $datadir.tempfiles.txt; list_files $datadir/mysql #sql*; --enable_query_log diff --git a/mysql-test/suite/innodb/r/alter_crash.result b/mysql-test/suite/innodb/r/alter_crash.result index 8de02cc5fbd..df1645a4ef6 100644 --- a/mysql-test/suite/innodb/r/alter_crash.result +++ b/mysql-test/suite/innodb/r/alter_crash.result @@ -44,10 +44,9 @@ SET DEBUG_DBUG='+d,innodb_alter_commit_crash_after_commit'; ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ERROR HY000: Lost connection to MySQL server during query # Restart mysqld after the crash and reconnect. -# Manual *.frm recovery begin. -# Manual recovery end -FLUSH TABLES; -# Drop the orphaned original table. +SELECT * FROM information_schema.innodb_sys_tables +WHERE table_id = ID; +TABLE_ID NAME FLAG N_COLS SPACE FILE_FORMAT ROW_FORMAT ZIP_PAGE_SIZE SPACE_TYPE # Files in datadir after manual recovery. t1.frm t1.ibd @@ -83,11 +82,9 @@ SET DEBUG_DBUG='+d,innodb_alter_commit_crash_before_commit'; ALTER TABLE t2 ADD PRIMARY KEY (f2, f1); ERROR HY000: Lost connection to MySQL server during query # Startup the server after the crash -# Read and remember the temporary table name -# Manual *.frm recovery begin. The dictionary was not updated -# and the files were not renamed. The rebuilt table -# was left behind on purpose, to faciliate data recovery. -# Manual recovery end +SELECT * FROM information_schema.innodb_sys_tables +WHERE name LIKE 'test/#sql-ib%'; +TABLE_ID NAME FLAG N_COLS SPACE FILE_FORMAT ROW_FORMAT ZIP_PAGE_SIZE SPACE_TYPE # Drop the orphaned rebuilt table. SHOW TABLES; Tables_in_test @@ -123,10 +120,10 @@ SET DEBUG_DBUG='+d,innodb_alter_commit_crash_after_commit'; ALTER TABLE t1 ADD INDEX (b), CHANGE c d int, ALGORITHM=INPLACE; ERROR HY000: Lost connection to MySQL server during query # Restart mysqld after the crash and reconnect. -# Manual *.frm recovery begin. -# Manual recovery end +SELECT * FROM information_schema.innodb_sys_tables +WHERE table_id = ID; +TABLE_ID NAME FLAG N_COLS SPACE FILE_FORMAT ROW_FORMAT ZIP_PAGE_SIZE SPACE_TYPE FLUSH TABLES; -# Drop the orphaned original table. # Files in datadir after manual recovery. t1.frm t1.ibd diff --git a/mysql-test/suite/innodb/r/drop_table_background.result b/mysql-test/suite/innodb/r/drop_table_background.result index a6f5672ba7f..e74bcd5e780 100644 --- a/mysql-test/suite/innodb/r/drop_table_background.result +++ b/mysql-test/suite/innodb/r/drop_table_background.result @@ -3,7 +3,22 @@ KEY(c1), KEY(c2), KEY(c2,c1), KEY(c3), KEY(c3,c1), KEY(c3,c2), KEY(c3,c2,c1), KEY(c4), KEY(c4,c1), KEY(c4,c2), KEY(c4,c2,c1), KEY(c4,c3), KEY(c4,c3,c1), KEY(c4,c3,c2), KEY(c4,c3,c2,c1)) ENGINE=InnoDB; +CREATE TABLE `#mysql50##sql-ib-foo`(a SERIAL) ENGINE=InnoDB; +INSERT INTO t (c1) VALUES (1),(2),(1); SET DEBUG_DBUG='+d,row_drop_table_add_to_background'; +CREATE TABLE target (PRIMARY KEY(c1)) ENGINE=InnoDB SELECT * FROM t; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +SELECT * from target; +ERROR 42S02: Table 'test.target' doesn't exist DROP TABLE t; CREATE TABLE t (a INT) ENGINE=InnoDB; DROP TABLE t; +DROP TABLE target; +ERROR 42S02: Unknown table 'test.target' +CREATE TABLE target (a INT) ENGINE=InnoDB; +DROP TABLE target; +SELECT * FROM `#mysql50##sql-ib-foo`; +ERROR 42S02: Table 'test.#mysql50##sql-ib-foo' doesn't exist in engine +DROP TABLE `#mysql50##sql-ib-foo`; +Warnings: +Warning 1932 Table 'test.#mysql50##sql-ib-foo' doesn't exist in engine diff --git a/mysql-test/suite/innodb/t/alter_crash.test b/mysql-test/suite/innodb/t/alter_crash.test index b4fdfd2f2d5..0b9e99721a7 100644 --- a/mysql-test/suite/innodb/t/alter_crash.test +++ b/mysql-test/suite/innodb/t/alter_crash.test @@ -75,28 +75,22 @@ ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); --echo # Restart mysqld after the crash and reconnect. --source include/start_mysqld.inc -let $temp_table_name = `SELECT SUBSTR(name, 6) - FROM information_schema.innodb_sys_tables - WHERE table_id = $orig_table_id`; - ---echo # Manual *.frm recovery begin. - ---move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/$temp_table_name.frm - +let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; perl; -my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm"; -my $t1_frm = "$ENV{'datadir'}/test/t1.frm"; -rename($frm_file[0], $t1_frm); +die unless open OUT, ">$ENV{TABLENAME_INC}"; +chdir "$ENV{'datadir'}/test"; +my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; +print OUT 'let $tablename=', $frm_file[0], ';'; +close OUT or die; EOF +source $TABLENAME_INC; +remove_file $TABLENAME_INC; ---echo # Manual recovery end +--replace_result $orig_table_id ID +eval SELECT * FROM information_schema.innodb_sys_tables +WHERE table_id = $orig_table_id; -FLUSH TABLES; - ---echo # Drop the orphaned original table. ---disable_query_log -eval DROP TABLE `#mysql50#$temp_table_name`; ---enable_query_log +move_file $datadir/test/$tablename.frm $datadir/test/t1.frm; --echo # Files in datadir after manual recovery. --list_files $MYSQLD_DATADIR/test @@ -134,14 +128,8 @@ ALTER TABLE t2 ADD PRIMARY KEY (f2, f1); --echo # Startup the server after the crash --source include/start_mysqld.inc ---echo # Read and remember the temporary table name -let $temp_table_name = `SELECT SUBSTRING(name,6) - FROM information_schema.innodb_sys_tables - WHERE name LIKE "test/#sql-ib$orig_table_id%"`; - ---echo # Manual *.frm recovery begin. The dictionary was not updated ---echo # and the files were not renamed. The rebuilt table ---echo # was left behind on purpose, to faciliate data recovery. +SELECT * FROM information_schema.innodb_sys_tables +WHERE name LIKE 'test/#sql-ib%'; let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; perl; @@ -154,8 +142,6 @@ EOF source $TABLENAME_INC; remove_file $TABLENAME_INC; ---echo # Manual recovery end - --echo # Drop the orphaned rebuilt table. --disable_query_log eval DROP TABLE `#mysql50#$tablename`; @@ -198,28 +184,24 @@ ALTER TABLE t1 ADD INDEX (b), CHANGE c d int, ALGORITHM=INPLACE; --echo # Restart mysqld after the crash and reconnect. --source include/start_mysqld.inc -let $temp_table_name = `SELECT SUBSTR(name, 6) - FROM information_schema.innodb_sys_tables - WHERE table_id = $orig_table_id`; - ---echo # Manual *.frm recovery begin. ---move_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/$temp_table_name.frm +--replace_result $orig_table_id ID +eval SELECT * FROM information_schema.innodb_sys_tables +WHERE table_id = $orig_table_id; perl; -my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm"; -my $t1_frm = "$ENV{'datadir'}/test/t1.frm"; -rename($frm_file[0], $t1_frm); +die unless open OUT, ">$ENV{TABLENAME_INC}"; +chdir "$ENV{'datadir'}/test"; +my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; +print OUT 'let $tablename=', $frm_file[0], ';'; +close OUT or die; EOF ---echo # Manual recovery end +source $TABLENAME_INC; +remove_file $TABLENAME_INC; +move_file $datadir/test/$tablename.frm $datadir/test/t1.frm; FLUSH TABLES; ---echo # Drop the orphaned original table. ---disable_query_log -eval DROP TABLE `#mysql50#$temp_table_name`; ---enable_query_log - --echo # Files in datadir after manual recovery. --list_files $MYSQLD_DATADIR/test diff --git a/mysql-test/suite/innodb/t/drop_table_background.test b/mysql-test/suite/innodb/t/drop_table_background.test index 0f596dec574..8d82bea9675 100644 --- a/mysql-test/suite/innodb/t/drop_table_background.test +++ b/mysql-test/suite/innodb/t/drop_table_background.test @@ -9,6 +9,9 @@ KEY(c3), KEY(c3,c1), KEY(c3,c2), KEY(c3,c2,c1), KEY(c4), KEY(c4,c1), KEY(c4,c2), KEY(c4,c2,c1), KEY(c4,c3), KEY(c4,c3,c1), KEY(c4,c3,c2), KEY(c4,c3,c2,c1)) ENGINE=InnoDB; +CREATE TABLE `#mysql50##sql-ib-foo`(a SERIAL) ENGINE=InnoDB; +INSERT INTO t (c1) VALUES (1),(2),(1); + let $n= 10; SET DEBUG_DBUG='+d,row_drop_table_add_to_background'; @@ -24,7 +27,18 @@ while ($i) { dec $i; } --enable_query_log +--error ER_DUP_ENTRY +CREATE TABLE target (PRIMARY KEY(c1)) ENGINE=InnoDB SELECT * FROM t; +--error ER_NO_SUCH_TABLE +SELECT * from target; DROP TABLE t; --source include/restart_mysqld.inc CREATE TABLE t (a INT) ENGINE=InnoDB; DROP TABLE t; +--error ER_BAD_TABLE_ERROR +DROP TABLE target; +CREATE TABLE target (a INT) ENGINE=InnoDB; +DROP TABLE target; +--error ER_NO_SUCH_TABLE_IN_ENGINE +SELECT * FROM `#mysql50##sql-ib-foo`; +DROP TABLE `#mysql50##sql-ib-foo`; diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 417aee02132..3a53c35ba8b 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -424,6 +424,10 @@ ulint row_get_background_drop_list_len_low(void); /*======================================*/ +/** Drop garbage tables during recovery. */ +void +row_mysql_drop_garbage_tables(); + /*********************************************************************//** Sets an exclusive lock on a table. @return error code or DB_SUCCESS */ diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index a1b031f5b1e..f28423ddde0 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -3732,6 +3732,8 @@ recv_recovery_rollback_active(void) /* Drop partially created indexes. */ row_merge_drop_temp_indexes(); + /* Drop garbage tables. */ + row_mysql_drop_garbage_tables(); /* Drop any auxiliary tables that were not dropped when the parent table was dropped. This can happen if the parent table diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 58d90cfb2ac..2b23ea8a230 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -65,6 +65,7 @@ Created 9/17/2000 Heikki Tuuri #include "trx0undo.h" #include "srv0start.h" #include "row0ext.h" +#include "srv0start.h" #include "ut0new.h" #include @@ -2634,12 +2635,6 @@ row_drop_table_for_mysql_in_background( error = row_drop_table_for_mysql(name, trx, SQLCOM_TRUNCATE); - /* Flush the log to reduce probability that the .frm files and - the InnoDB data dictionary get out-of-sync if the user runs - with innodb_flush_log_at_trx_commit = 0 */ - - log_buffer_flush_to_disk(); - trx_commit_for_mysql(trx); trx_free_for_background(trx); @@ -2677,8 +2672,11 @@ next: return(n_tables + n_tables_dropped); } - table = dict_table_open_on_id(drop->table_id, FALSE, - DICT_TABLE_OP_OPEN_ONLY_IF_CACHED); + /* On fast shutdown, just empty the list without dropping tables. */ + table = srv_shutdown_state == SRV_SHUTDOWN_NONE || !srv_fast_shutdown + ? dict_table_open_on_id(drop->table_id, FALSE, + DICT_TABLE_OP_OPEN_ONLY_IF_CACHED) + : NULL; if (!table) { n_tables_dropped++; @@ -2733,6 +2731,75 @@ row_get_background_drop_list_len_low(void) return(len); } +/** Drop garbage tables during recovery. */ +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_allocate_for_background(); + trx->op_info = "dropping garbage tables"; + row_mysql_lock_data_dictionary(trx); + + mtr.start(); + btr_pcur_open_at_index_side( + true, dict_table_get_first_index(dict_sys->sys_tables), + BTR_SEARCH_LEAF, &pcur, true, 0, &mtr); + + for (;;) { + const rec_t* rec; + const byte* field; + ulint len; + const char* table_name; + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) { + break; + } + + rec = btr_pcur_get_rec(&pcur); + if (rec_get_deleted_flag(rec, 0)) { + continue; + } + + field = rec_get_nth_field_old(rec, 0/*NAME*/, &len); + if (len == UNIV_SQL_NULL || len == 0) { + /* 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, true, + DICT_ERR_IGNORE_ALL)) { + row_drop_table_for_mysql( + table_name, trx, + SQLCOM_DROP_TABLE); + trx_commit_for_mysql(trx); + } + + mtr.start(); + btr_pcur_restore_position(BTR_SEARCH_LEAF, + &pcur, &mtr); + } + + mem_heap_empty(heap); + } + + btr_pcur_close(&pcur); + mtr.commit(); + row_mysql_unlock_data_dictionary(trx); + trx_free_for_background(trx); + mem_heap_free(heap); +} + /*********************************************************************//** If a table is not yet in the drop list, adds the table to the list of tables which the master thread drops in background. We need this on Unix because in @@ -3537,11 +3604,8 @@ row_drop_table_for_mysql( } } - DBUG_EXECUTE_IF("row_drop_table_add_to_background", - row_add_table_to_background_drop_list(table->id); - err = DB_SUCCESS; - goto funct_exit; - ); + + DBUG_EXECUTE_IF("row_drop_table_add_to_background", goto defer;); /* TODO: could we replace the counter n_foreign_key_checks_running with lock checks on the table? Acquire here an exclusive lock on the @@ -3550,17 +3614,22 @@ row_drop_table_for_mysql( checks take an IS or IX lock on the table. */ if (table->n_foreign_key_checks_running > 0) { - if (row_add_table_to_background_drop_list(table->id)) { - ib::info() << "You are trying to drop table " - << table->name - << " though there is a foreign key check" - " running on it. Adding the table to the" - " background drop queue."; +defer: + if (!strstr(table->name.m_name, "/" TEMP_FILE_PREFIX_INNODB)) { + heap = mem_heap_create(FN_REFLEN); + const char* tmp_name + = dict_mem_create_temporary_tablename( + heap, table->name.m_name, table->id); + ib::info() << "Deferring DROP TABLE " << table->name + << "; renaming to " << tmp_name; + err = row_rename_table_for_mysql( + table->name.m_name, tmp_name, trx, false); + } else { + err = DB_SUCCESS; + } + if (err == DB_SUCCESS) { + row_add_table_to_background_drop_list(table->id); } - - /* We return DB_SUCCESS to MySQL though the drop will - happen lazily later */ - err = DB_SUCCESS; goto funct_exit; } @@ -3581,29 +3650,9 @@ row_drop_table_for_mysql( /* Wait on background threads to stop using table */ fil_wait_crypt_bg_threads(table); - if (table->get_ref_count() == 0) { - lock_remove_all_on_table(table, TRUE); - ut_a(table->n_rec_locks == 0); - } else if (table->get_ref_count() > 0 || table->n_rec_locks > 0) { - if (row_add_table_to_background_drop_list(table->id)) { - if (!strstr(table->name.m_name, - "/" TEMP_FILE_PREFIX_INNODB)) { - ib::info() << "MySQL is trying to drop table " - << table->name - << " though there are still " - "open handles to it. Adding the table " - "to the background drop queue."; - } - - /* We return DB_SUCCESS to MySQL though the drop will - happen lazily later */ - err = DB_SUCCESS; - } else { - /* The table is already in the background drop list */ - err = DB_ERROR; - } - - goto funct_exit; + if (table->get_ref_count() > 0 || table->n_rec_locks > 0 + || lock_table_has_locks(table)) { + goto defer; } /* The "to_be_dropped" marks table that is to be dropped, but @@ -3613,11 +3662,6 @@ row_drop_table_for_mysql( and it is free to be dropped */ table->to_be_dropped = false; - /* If we get this far then the table to be dropped must not have - any table or record locks on it. */ - - ut_a(!lock_table_has_locks(table)); - switch (trx_get_dict_operation(trx)) { case TRX_DICT_OP_NONE: trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); From 73ed19e44f57853c01936a4bcb8c4ad8cfb7242c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 6 Sep 2018 11:51:50 +0300 Subject: [PATCH 6/7] MDEV-14585 Automatically remove #sql- tables in InnoDB dictionary during recovery This is a backport of the following commits: commit b4165985c97a4133e19dd99b459dea27f87fbb1b commit 69e88de0fe6dc5312f5d6e7a179a5ab73d60dc43 commit 40f4525f43aba5d579cf55bae2df504001cd04f4 commit 656f66def27b7a2cf42a28f873f1eeef0416aa71 Now that MDEV-14717 made RENAME TABLE crash-safe within InnoDB, it should be safe to drop the #sql- tables within InnoDB during crash recovery. These tables can be one of two things: (1) #sql-ib related to deferred DROP TABLE (follow-up to MDEV-13407) or to table-rebuilding ALTER TABLE...ALGORITHM=INPLACE (since MDEV-14378, only related to the intermediate copy of a table), (2) #sql- related to the intermediate copy of a table during ALTER TABLE...ALGORITHM=COPY We will not drop tables whose name starts with #sql2, because the server can be killed during an ALGORITHM=COPY operation at a point where the original table was renamed to #sql2 but the finished intermediate copy was not yet renamed from #sql- to the original table name. If an old version of MariaDB Server before 10.2.13 (MDEV-11415) was killed while ALTER TABLE...ALGORITHM=COPY was in progress, after recovery there could be undo log records for some records that were inserted into an intermediate copy of the table. Due to these undo log records, InnoDB would resurrect locks at recovery, and the intermediate table would be locked while we are trying to drop it. This would cause a call to row_rename_table_for_mysql(), either from row_mysql_drop_garbage_tables() or from the rollback of a RENAME operation that was part of the ALTER TABLE. row_rename_table_for_mysql(): Do not attempt to parse FOREIGN KEY constraints when renaming from #sql-something to #sql-something-else, because it does not make any sense. row_drop_table_for_mysql(): When deferring DROP TABLE due to locks, do not rename the table if its name already starts with the #sql- prefix, which is what row_mysql_drop_garbage_tables() uses. Previously, the too strict prefix #sql-ib was used, and some tables were renamed unnecessarily. --- mysql-test/suite/innodb/r/alter_copy.result | 2 - mysql-test/suite/innodb/r/alter_crash.result | 4 +- .../innodb/r/innodb-alter-tempfile.result | 1 + .../suite/innodb/r/rename_table_debug.result | 9 ++-- .../suite/innodb/r/truncate_crash.result | 14 ++++++ mysql-test/suite/innodb/t/alter_copy.test | 6 +-- mysql-test/suite/innodb/t/alter_crash.test | 46 ++++++------------- .../suite/innodb/t/innodb-alter-tempfile.test | 15 +----- .../suite/innodb/t/rename_table_debug.test | 7 ++- mysql-test/suite/innodb/t/truncate_crash.test | 22 +++++++++ storage/innobase/handler/ha_innodb.cc | 6 +-- storage/innobase/row/row0mysql.cc | 6 +-- 12 files changed, 70 insertions(+), 68 deletions(-) create mode 100644 mysql-test/suite/innodb/r/truncate_crash.result create mode 100644 mysql-test/suite/innodb/t/truncate_crash.test diff --git a/mysql-test/suite/innodb/r/alter_copy.result b/mysql-test/suite/innodb/r/alter_copy.result index 9815560d22c..286c5152ded 100644 --- a/mysql-test/suite/innodb/r/alter_copy.result +++ b/mysql-test/suite/innodb/r/alter_copy.result @@ -183,7 +183,6 @@ CHECK TABLE t1; Table Op Msg_type Msg_text test.t1 check status OK #sql-temporary.frm -#sql-temporary.ibd FTS_INDEX_1.ibd FTS_INDEX_2.ibd FTS_INDEX_3.ibd @@ -212,4 +211,3 @@ t.ibd t1.frm t1.ibd DROP TABLE t1,t; -DROP TABLE `#mysql50##sql-temporary`; diff --git a/mysql-test/suite/innodb/r/alter_crash.result b/mysql-test/suite/innodb/r/alter_crash.result index df1645a4ef6..3b6a5d1b39a 100644 --- a/mysql-test/suite/innodb/r/alter_crash.result +++ b/mysql-test/suite/innodb/r/alter_crash.result @@ -83,9 +83,8 @@ ALTER TABLE t2 ADD PRIMARY KEY (f2, f1); ERROR HY000: Lost connection to MySQL server during query # Startup the server after the crash SELECT * FROM information_schema.innodb_sys_tables -WHERE name LIKE 'test/#sql-ib%'; +WHERE name LIKE 'test/#sql-%'; TABLE_ID NAME FLAG N_COLS SPACE FILE_FORMAT ROW_FORMAT ZIP_PAGE_SIZE SPACE_TYPE -# Drop the orphaned rebuilt table. SHOW TABLES; Tables_in_test t2 @@ -123,7 +122,6 @@ ERROR HY000: Lost connection to MySQL server during query SELECT * FROM information_schema.innodb_sys_tables WHERE table_id = ID; TABLE_ID NAME FLAG N_COLS SPACE FILE_FORMAT ROW_FORMAT ZIP_PAGE_SIZE SPACE_TYPE -FLUSH TABLES; # Files in datadir after manual recovery. t1.frm t1.ibd diff --git a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result index b164c3c26b0..3b797559603 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result +++ b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result @@ -8,6 +8,7 @@ CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb; SET debug_dbug='+d,innodb_alter_commit_crash_before_commit'; ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ERROR HY000: Lost connection to MySQL server during query +# Startup the server after the crash show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/suite/innodb/r/rename_table_debug.result b/mysql-test/suite/innodb/r/rename_table_debug.result index 912ed9de48b..646bd4faf5d 100644 --- a/mysql-test/suite/innodb/r/rename_table_debug.result +++ b/mysql-test/suite/innodb/r/rename_table_debug.result @@ -1,5 +1,6 @@ -CREATE TABLE t1 (a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t1 VALUES(42); +FLUSH TABLES; +CREATE TABLE t1 (a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB; +INSERT INTO t1 () VALUES (); connect con1,localhost,root,,test; SET DEBUG_SYNC='before_rename_table_commit SIGNAL renamed WAIT_FOR ever'; RENAME TABLE t1 TO t2; @@ -7,6 +8,6 @@ connection default; SET DEBUG_SYNC='now WAIT_FOR renamed'; disconnect con1; SELECT * FROM t1; -a -42 +a b c d +1 NULL NULL NULL DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/truncate_crash.result b/mysql-test/suite/innodb/r/truncate_crash.result new file mode 100644 index 00000000000..6c20da46cf8 --- /dev/null +++ b/mysql-test/suite/innodb/r/truncate_crash.result @@ -0,0 +1,14 @@ +FLUSH TABLES; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 SET a=1; +connect wait,localhost,root,,test; +SET DEBUG_SYNC='after_trx_committed_in_memory SIGNAL c WAIT_FOR ever'; +TRUNCATE TABLE t1; +connection default; +SET DEBUG_SYNC='now WAIT_FOR c'; +disconnect wait; +SELECT * FROM t1; +a +1 +TRUNCATE TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/alter_copy.test b/mysql-test/suite/innodb/t/alter_copy.test index b1c71d82096..0dce61994b5 100644 --- a/mysql-test/suite/innodb/t/alter_copy.test +++ b/mysql-test/suite/innodb/t/alter_copy.test @@ -88,8 +88,4 @@ CHECK TABLE t1; DROP TABLE t1,t; # Work around missing crash recovery at the SQL layer. -let $temp_table_name = `SELECT SUBSTRING(name,6) - FROM information_schema.innodb_sys_tables - WHERE name LIKE "test/#sql-%"`; ---replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ -eval DROP TABLE `#mysql50#$temp_table_name`; +--remove_files_wildcard $datadir/test #sql-*.frm diff --git a/mysql-test/suite/innodb/t/alter_crash.test b/mysql-test/suite/innodb/t/alter_crash.test index 0b9e99721a7..101e0fa44c2 100644 --- a/mysql-test/suite/innodb/t/alter_crash.test +++ b/mysql-test/suite/innodb/t/alter_crash.test @@ -72,9 +72,6 @@ let $orig_table_id = `SELECT table_id --error 2013 ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ---echo # Restart mysqld after the crash and reconnect. ---source include/start_mysqld.inc - let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; perl; die unless open OUT, ">$ENV{TABLENAME_INC}"; @@ -86,12 +83,15 @@ EOF source $TABLENAME_INC; remove_file $TABLENAME_INC; +move_file $datadir/test/$tablename.frm $datadir/test/t1.frm; + +--echo # Restart mysqld after the crash and reconnect. +--source include/start_mysqld.inc + --replace_result $orig_table_id ID eval SELECT * FROM information_schema.innodb_sys_tables WHERE table_id = $orig_table_id; -move_file $datadir/test/$tablename.frm $datadir/test/t1.frm; - --echo # Files in datadir after manual recovery. --list_files $MYSQLD_DATADIR/test @@ -125,27 +125,13 @@ let $orig_table_id = `SELECT table_id --error 2013 ALTER TABLE t2 ADD PRIMARY KEY (f2, f1); +remove_files_wildcard $datadir/test #sql-*.frm; + --echo # Startup the server after the crash --source include/start_mysqld.inc SELECT * FROM information_schema.innodb_sys_tables -WHERE name LIKE 'test/#sql-ib%'; - -let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; -perl; -die unless open OUT, ">$ENV{TABLENAME_INC}"; -chdir "$ENV{'datadir'}/test"; -my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; -print OUT 'let $tablename=', $frm_file[0], ';'; -close OUT or die; -EOF -source $TABLENAME_INC; -remove_file $TABLENAME_INC; - ---echo # Drop the orphaned rebuilt table. ---disable_query_log -eval DROP TABLE `#mysql50#$tablename`; ---enable_query_log +WHERE name LIKE 'test/#sql-%'; SHOW TABLES; INSERT INTO t2 VALUES (5,6),(7,8); @@ -181,13 +167,6 @@ let $orig_table_id = `select table_id from --error 2013 ALTER TABLE t1 ADD INDEX (b), CHANGE c d int, ALGORITHM=INPLACE; ---echo # Restart mysqld after the crash and reconnect. ---source include/start_mysqld.inc - ---replace_result $orig_table_id ID -eval SELECT * FROM information_schema.innodb_sys_tables -WHERE table_id = $orig_table_id; - perl; die unless open OUT, ">$ENV{TABLENAME_INC}"; chdir "$ENV{'datadir'}/test"; @@ -195,12 +174,17 @@ my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; print OUT 'let $tablename=', $frm_file[0], ';'; close OUT or die; EOF - source $TABLENAME_INC; remove_file $TABLENAME_INC; + move_file $datadir/test/$tablename.frm $datadir/test/t1.frm; -FLUSH TABLES; +--echo # Restart mysqld after the crash and reconnect. +--source include/start_mysqld.inc + +--replace_result $orig_table_id ID +eval SELECT * FROM information_schema.innodb_sys_tables +WHERE table_id = $orig_table_id; --echo # Files in datadir after manual recovery. --list_files $MYSQLD_DATADIR/test diff --git a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test index f2038da8c4c..de27c7ebf62 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test +++ b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test @@ -31,25 +31,14 @@ SET debug_dbug='+d,innodb_alter_commit_crash_before_commit'; --error 2013 ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); +--echo # Startup the server after the crash -let TABLENAME_INC= $MYSQLTEST_VARDIR/tmp/tablename.inc; -perl; -die unless open OUT, ">$ENV{TABLENAME_INC}"; -chdir "$ENV{'datadir'}/test"; -my @frm_file = map { substr($_, 0, -4) } glob "#sql-*.frm"; -print OUT 'let $temp_table_name=', $frm_file[0], ';'; -close OUT or die; -EOF -source $TABLENAME_INC; -remove_file $TABLENAME_INC; +remove_files_wildcard $datadir/test #sql-*.frm; --source include/start_mysqld.inc show create table t1; --echo # Consecutive Alter table does not create same temporary file name ALTER TABLE t1 ADD PRIMARY KEY (f2, f1); ---disable_query_log -eval DROP TABLE `#mysql50#$temp_table_name`; ---enable_query_log show create table t1; drop table t1; diff --git a/mysql-test/suite/innodb/t/rename_table_debug.test b/mysql-test/suite/innodb/t/rename_table_debug.test index 4620f7bef22..c75f2fbca10 100644 --- a/mysql-test/suite/innodb/t/rename_table_debug.test +++ b/mysql-test/suite/innodb/t/rename_table_debug.test @@ -3,8 +3,11 @@ --source include/have_debug_sync.inc --source include/not_embedded.inc -CREATE TABLE t1 (a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t1 VALUES(42); +FLUSH TABLES; +LET $datadir= `SELECT @@datadir`; + +CREATE TABLE t1 (a SERIAL, b INT, c INT, d INT) ENGINE=InnoDB; +INSERT INTO t1 () VALUES (); --connect (con1,localhost,root,,test) SET DEBUG_SYNC='before_rename_table_commit SIGNAL renamed WAIT_FOR ever'; diff --git a/mysql-test/suite/innodb/t/truncate_crash.test b/mysql-test/suite/innodb/t/truncate_crash.test new file mode 100644 index 00000000000..15ba475e0e1 --- /dev/null +++ b/mysql-test/suite/innodb/t/truncate_crash.test @@ -0,0 +1,22 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/not_embedded.inc + +FLUSH TABLES; +CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 SET a=1; + +connect (wait,localhost,root,,test); +SET DEBUG_SYNC='after_trx_committed_in_memory SIGNAL c WAIT_FOR ever'; +send TRUNCATE TABLE t1; + +connection default; +SET DEBUG_SYNC='now WAIT_FOR c'; +--let $shutdown_timeout=0 +--source include/restart_mysqld.inc +disconnect wait; + +SELECT * FROM t1; +TRUNCATE TABLE t1; +DROP TABLE t1; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 7bb84b41a11..e29e1b0ed4b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13509,11 +13509,7 @@ int ha_innobase::truncate() if (!err) { /* Reopen the newly created table, and drop the - original table that was renamed to temp_name. - - Note: In MariaDB 10.2 (before MDEV-14585), if the - server is killed and restarted before the original - table is dropped, the table will remain orphaned. */ + original table that was renamed to temp_name. */ close(); err = open(name, 0, 0); if (!err) { diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2b23ea8a230..d51c2539f3e 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2773,7 +2773,7 @@ row_mysql_drop_garbage_tables() table_name = mem_heap_strdupl( heap, reinterpret_cast(field), len); - if (strstr(table_name, "/" TEMP_FILE_PREFIX_INNODB)) { + if (strstr(table_name, "/" TEMP_FILE_PREFIX "-")) { btr_pcur_store_position(&pcur, &mtr); btr_pcur_commit_specify_mtr(&pcur, &mtr); @@ -3615,7 +3615,7 @@ row_drop_table_for_mysql( if (table->n_foreign_key_checks_running > 0) { defer: - if (!strstr(table->name.m_name, "/" TEMP_FILE_PREFIX_INNODB)) { + if (!strstr(table->name.m_name, "/" TEMP_FILE_PREFIX)) { heap = mem_heap_create(FN_REFLEN); const char* tmp_name = dict_mem_create_temporary_tablename( @@ -4399,7 +4399,7 @@ row_rename_table_for_mysql( goto funct_exit; - } else if (new_is_tmp) { + } else if (!old_is_tmp && new_is_tmp) { /* MySQL is doing an ALTER TABLE command and it renames the original table to a temporary table name. We want to preserve the original foreign key constraint definitions despite the From 980d1bf1a921a270423ab36bd5d1ce2a1cd7590b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 7 Sep 2018 17:24:31 +0300 Subject: [PATCH 7/7] MDEV-14717: Prevent crash-downgrade to earlier MariaDB 10.2 A crash-downgrade of a RENAME (or TRUNCATE or table-rebuilding ALTER TABLE or OPTIMIZE TABLE) operation to an earlier 10.2 version would trigger a debug assertion failure during rollback, in trx_roll_pop_top_rec_of_trx(). In a non-debug build, the TRX_UNDO_RENAME_TABLE record would be misinterpreted as an update_undo log record, and typically the file name would be interpreted as DB_TRX_ID,DB_ROLL_PTR,PRIMARY KEY. If a matching record would be found, row_undo_mod() would hit ut_error in switch (node->rec_type). Typically, ut_a(table2 == NULL) would fail when opening the table from SQL. Because of this, we prevent a crash-downgrade to earlier MariaDB 10.2 versions by changing the InnoDB redo log format identifier to the 10.3 identifier, and by introducing a subformat identifier so that 10.2 can continue to refuse crash-downgrade from 10.3 or later. After a clean shutdown, a downgrade to MariaDB 10.2.13 or later would still be possible thanks to MDEV-14909. A downgrade to older 10.2 versions is only possible after removing the log files (not recommended). LOG_HEADER_FORMAT_CURRENT: Change to 103 (originally the 10.3 format). log_group_t: Add subformat. For 10.2, we will use subformat 1, and will refuse crash recovery from any other subformat of the 10.3 format, that is, a genuine 10.3 redo log. recv_find_max_checkpoint(): Allow startup after clean shutdown from a future LOG_HEADER_FORMAT_10_4 (unencrypted only). We cannot handle the encrypted 10.4 redo log block format, which was introduced in MDEV-12041. Allow crash recovery from the original 10.2 format as well as the new format. In Mariabackup --backup, do not allow any startup from 10.3 or 10.4 redo logs. recv_recovery_from_checkpoint_start(): Skip redo log apply for clean 10.3 redo log, but not for the new 10.2 redo log (10.3 format, subformat 1). srv_prepare_to_delete_redo_log_files(): On format or subformat mismatch, set srv_log_file_size = 0, so that we will display the correct message. innobase_start_or_create_for_mysql(): Check for format or subformat mismatch. xtrabackup_backup_func(): Remove debug assertions that were made redundant by the code changes in recv_find_max_checkpoint(). --- extra/mariabackup/xtrabackup.cc | 9 ++--- storage/innobase/include/log0log.h | 20 ++++++++--- storage/innobase/log/log0log.cc | 3 +- storage/innobase/log/log0recv.cc | 56 +++++++++++++++++++++++------- storage/innobase/srv/srv0start.cc | 18 ++++++++-- 5 files changed, 78 insertions(+), 28 deletions(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 1faa10f9c7a..5b3fe9fe435 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4139,9 +4139,6 @@ old_format: goto log_fail; } - ut_ad(!((log_sys->log.format ^ LOG_HEADER_FORMAT_CURRENT) - & ~LOG_HEADER_FORMAT_ENCRYPTED)); - const byte* buf = log_sys->checkpoint_buf; reread_log_header: @@ -4158,9 +4155,6 @@ reread_log_header: goto old_format; } - ut_ad(!((log_sys->log.format ^ LOG_HEADER_FORMAT_CURRENT) - & ~LOG_HEADER_FORMAT_ENCRYPTED)); - log_group_header_read(&log_sys->log, max_cp_field); if (checkpoint_no_start != mach_read_from_8(buf + LOG_CHECKPOINT_NO)) { @@ -4188,7 +4182,8 @@ reread_log_header: byte MY_ALIGNED(OS_FILE_LOG_BLOCK_SIZE) log_hdr[OS_FILE_LOG_BLOCK_SIZE]; memset(log_hdr, 0, sizeof log_hdr); mach_write_to_4(LOG_HEADER_FORMAT + log_hdr, log_sys->log.format); - mach_write_to_4(LOG_HEADER_SUBFORMAT + log_hdr, 1); + mach_write_to_4(LOG_HEADER_SUBFORMAT + log_hdr, + log_sys->log.subformat); mach_write_to_8(LOG_HEADER_START_LSN + log_hdr, checkpoint_lsn_start); strcpy(reinterpret_cast(LOG_HEADER_CREATOR + log_hdr), "Backup " MYSQL_SERVER_VERSION); diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index cd3f415a8d7..4759e5a85f4 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -513,10 +513,17 @@ or the MySQL version that created the redo log file. */ IB_TO_STR(MYSQL_VERSION_PATCH) /** The redo log format identifier corresponding to the current format version. -Stored in LOG_HEADER_FORMAT. */ -#define LOG_HEADER_FORMAT_CURRENT 1 -/** The MariaDB 10.3.2 log format */ -#define LOG_HEADER_FORMAT_10_3 103 +Stored in LOG_HEADER_FORMAT. +To prevent crash-downgrade to earlier 10.2 due to the inability to +roll back a retroactively introduced TRX_UNDO_RENAME_TABLE undo log record, +MariaDB 10.2.18 and later will use the 10.3 format, but LOG_HEADER_SUBFORMAT +1 instead of 0. MariaDB 10.3 will use subformat 0 (5.7-style TRUNCATE) or 2 +(MDEV-13564 backup-friendly TRUNCATE). */ +#define LOG_HEADER_FORMAT_CURRENT 103 +/** The old MariaDB 10.2.2..10.2.17 log format */ +#define LOG_HEADER_FORMAT_10_2 1 +/** Future MariaDB 10.4 log format */ +#define LOG_HEADER_FORMAT_10_4 104 /** Encrypted MariaDB redo log */ #define LOG_HEADER_FORMAT_ENCRYPTED (1U<<31) @@ -553,7 +560,10 @@ struct log_group_t{ /** number of files in the group */ ulint n_files; /** format of the redo log: e.g., LOG_HEADER_FORMAT_CURRENT */ - ulint format; + uint32_t format; + /** redo log subformat: 0 with separately logged TRUNCATE, + 1 with fully redo-logged TRUNCATE */ + uint32_t subformat; /** individual log file size in bytes, including the header */ lsn_t file_size; /** corruption status */ diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 209decae021..95c637bccfd 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -793,6 +793,7 @@ log_init(ulint n_files) group->format = srv_encrypt_log ? LOG_HEADER_FORMAT_CURRENT | LOG_HEADER_FORMAT_ENCRYPTED : LOG_HEADER_FORMAT_CURRENT; + group->subformat = 1; group->file_size = srv_log_file_size; group->state = LOG_GROUP_OK; group->lsn = LOG_START_LSN; @@ -880,7 +881,7 @@ log_group_file_header_flush( memset(buf, 0, OS_FILE_LOG_BLOCK_SIZE); mach_write_to_4(buf + LOG_HEADER_FORMAT, group->format); - mach_write_to_4(buf + LOG_HEADER_SUBFORMAT, 1); + mach_write_to_4(buf + LOG_HEADER_SUBFORMAT, group->subformat); mach_write_to_8(buf + LOG_HEADER_START_LSN, start_lsn); strcpy(reinterpret_cast(buf) + LOG_HEADER_CREATOR, LOG_HEADER_CREATOR_CURRENT); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index f28423ddde0..a69b425fdf4 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1147,6 +1147,9 @@ recv_find_max_checkpoint(ulint* max_field) /* Check the header page checksum. There was no checksum in the first redo log format (version 0). */ group->format = mach_read_from_4(buf + LOG_HEADER_FORMAT); + group->subformat = group->format + ? mach_read_from_4(buf + LOG_HEADER_SUBFORMAT) + : 0; if (group->format != 0 && !recv_check_log_header_checksum(buf)) { ib::error() << "Invalid redo log header checksum."; @@ -1164,8 +1167,11 @@ recv_find_max_checkpoint(ulint* max_field) return(recv_find_max_checkpoint_0(&group, max_field)); case LOG_HEADER_FORMAT_CURRENT: case LOG_HEADER_FORMAT_CURRENT | LOG_HEADER_FORMAT_ENCRYPTED: - case LOG_HEADER_FORMAT_10_3: - case LOG_HEADER_FORMAT_10_3 | LOG_HEADER_FORMAT_ENCRYPTED: + case LOG_HEADER_FORMAT_10_2: + case LOG_HEADER_FORMAT_10_2 | LOG_HEADER_FORMAT_ENCRYPTED: + case LOG_HEADER_FORMAT_10_4: + /* We can only parse the unencrypted LOG_HEADER_FORMAT_10_4. + The encrypted format uses a larger redo log block trailer. */ break; default: ib::error() << "Unsupported redo log format." @@ -1240,8 +1246,20 @@ recv_find_max_checkpoint(ulint* max_field) } switch (group->format) { - case LOG_HEADER_FORMAT_10_3: - case LOG_HEADER_FORMAT_10_3 | LOG_HEADER_FORMAT_ENCRYPTED: + case LOG_HEADER_FORMAT_CURRENT: + case LOG_HEADER_FORMAT_CURRENT | LOG_HEADER_FORMAT_ENCRYPTED: + if (group->subformat == 1) { + /* 10.2 with new crash-safe TRUNCATE */ + break; + } + /* fall through */ + case LOG_HEADER_FORMAT_10_4: + if (srv_operation == SRV_OPERATION_BACKUP) { + ib::error() + << "Incompatible redo log format." + " The redo log was created with " << creator; + return DB_ERROR; + } dberr_t err = recv_log_recover_10_3(); if (err != DB_SUCCESS) { ib::error() @@ -3370,7 +3388,6 @@ of first system tablespace page dberr_t recv_recovery_from_checkpoint_start(lsn_t flush_lsn) { - log_group_t* group; ulint max_cp_field; lsn_t checkpoint_lsn; bool rescan; @@ -3402,15 +3419,30 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) err = recv_find_max_checkpoint(&max_cp_field); - if (err != DB_SUCCESS - || (log_sys->log.format != 0 - && (log_sys->log.format & ~LOG_HEADER_FORMAT_ENCRYPTED) - != LOG_HEADER_FORMAT_CURRENT)) { - + if (err != DB_SUCCESS) { +skip_apply: log_mutex_exit(); return(err); } + switch (log_sys->log.format) { + case 0: + break; + case LOG_HEADER_FORMAT_10_2: + case LOG_HEADER_FORMAT_10_2 | LOG_HEADER_FORMAT_ENCRYPTED: + break; + case LOG_HEADER_FORMAT_CURRENT: + case LOG_HEADER_FORMAT_CURRENT | LOG_HEADER_FORMAT_ENCRYPTED: + if (log_sys->log.subformat == 1) { + /* 10.2 with new crash-safe TRUNCATE */ + break; + } + /* fall through */ + default: + /* This must be a clean log from a newer version. */ + goto skip_apply; + } + log_group_header_read(&log_sys->log, max_cp_field); buf = log_sys->checkpoint_buf; @@ -3426,13 +3458,12 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) ut_ad(RECV_SCAN_SIZE <= log_sys->buf_size); - group = &log_sys->log; const lsn_t end_lsn = mach_read_from_8( buf + LOG_CHECKPOINT_END_LSN); ut_ad(recv_sys->n_addrs == 0); contiguous_lsn = checkpoint_lsn; - switch (group->format) { + switch (log_sys->log.format) { case 0: log_mutex_exit(); return recv_log_format_0_recover(checkpoint_lsn, @@ -3451,6 +3482,7 @@ recv_recovery_from_checkpoint_start(lsn_t flush_lsn) } /* Look for MLOG_CHECKPOINT. */ + log_group_t* group = &log_sys->log; recv_group_scan_log_recs(group, checkpoint_lsn, &contiguous_lsn, false); /* The first scan should not have stored or applied any records. */ diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index cda652a9855..ca0e1472aed 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1393,6 +1393,12 @@ srv_prepare_to_delete_redo_log_files( ulint pending_io = 0; ulint count = 0; + if ((log_sys->log.format & ~LOG_HEADER_FORMAT_ENCRYPTED) + != LOG_HEADER_FORMAT_CURRENT + || log_sys->log.subformat != 1) { + srv_log_file_size = 0; + } + do { /* Clean the buffer pool. */ buf_flush_sync_all_buf_pools(); @@ -1411,7 +1417,7 @@ srv_prepare_to_delete_redo_log_files( if (srv_log_file_size == 0) { info << ((log_sys->log.format & ~LOG_HEADER_FORMAT_ENCRYPTED) - != LOG_HEADER_FORMAT_10_3 + < LOG_HEADER_FORMAT_CURRENT ? "Upgrading redo log: " : "Downgrading redo log: "); } else if (n_files != srv_n_log_files @@ -2385,8 +2391,14 @@ files_checked: /* Leave the redo log alone. */ } else if (srv_log_file_size_requested == srv_log_file_size && srv_n_log_files_found == srv_n_log_files - && log_sys->is_encrypted() == srv_encrypt_log) { - /* No need to upgrade or resize the redo log. */ + && log_sys->log.format + == (srv_encrypt_log + ? LOG_HEADER_FORMAT_CURRENT + | LOG_HEADER_FORMAT_ENCRYPTED + : LOG_HEADER_FORMAT_CURRENT) + && log_sys->log.subformat == 1) { + /* No need to add or remove encryption, + upgrade, downgrade, or resize. */ } else { /* Prepare to delete the old redo log files */ flushed_lsn = srv_prepare_to_delete_redo_log_files(i);