diff options
24 files changed, 701 insertions, 171 deletions
diff --git a/extra/mariabackup/write_filt.cc b/extra/mariabackup/write_filt.cc index 8339286e1df..4871e65e3c6 100644 --- a/extra/mariabackup/write_filt.cc +++ b/extra/mariabackup/write_filt.cc @@ -129,6 +129,18 @@ wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile) incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN)) continue; + /* Check whether TRX_SYS page has been changed */ + if (mach_read_from_4(page + FIL_PAGE_SPACE_ID) + == TRX_SYS_SPACE + && mach_read_from_4(page + FIL_PAGE_OFFSET) + == TRX_SYS_PAGE_NO) { + msg(cursor->thread_n, + "--incremental backup is impossible if " + "the server had been restarted with " + "different innodb_undo_tablespaces."); + return false; + } + /* updated page */ if (cp->npages == page_size / 4) { /* flush buffer */ diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 4d2da0082aa..18342bfa9e2 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3801,89 +3801,6 @@ next_datadir_item: return(err); } -/** Assign srv_undo_space_id_start variable if there are undo tablespace present. -Read the TRX_SYS page from ibdata1 file and get the minimum space id from -the first slot rollback segments of TRX_SYS_PAGE_NO. -@retval DB_ERROR if file open or page read failed. -@retval DB_SUCCESS if srv_undo_space_id assigned successfully. */ -static dberr_t xb_assign_undo_space_start() -{ - - pfs_os_file_t file; - bool ret; - dberr_t error = DB_SUCCESS; - ulint space; - int n_retries = 5; - ulint fsp_flags; - - if (srv_undo_tablespaces == 0) { - return error; - } - - file = os_file_create(0, srv_sys_space.first_datafile()->filepath(), - OS_FILE_OPEN, OS_FILE_NORMAL, OS_DATA_FILE, true, &ret); - - if (!ret) { - msg("Error opening %s", srv_sys_space.first_datafile()->filepath()); - return DB_ERROR; - } - - byte* page = static_cast<byte*> - (aligned_malloc(srv_page_size, srv_page_size)); - - if (os_file_read(IORequestRead, file, page, 0, srv_page_size) - != DB_SUCCESS) { - msg("Reading first page failed.\n"); - error = DB_ERROR; - goto func_exit; - } - - fsp_flags = mach_read_from_4( - page + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS); -retry: - if (os_file_read(IORequestRead, file, page, - TRX_SYS_PAGE_NO << srv_page_size_shift, - srv_page_size) != DB_SUCCESS) { - msg("Reading TRX_SYS page failed."); - error = DB_ERROR; - goto func_exit; - } - - /* TRX_SYS page can't be compressed or encrypted. */ - if (buf_page_is_corrupted(false, page, fsp_flags)) { - if (n_retries--) { - std::this_thread::sleep_for( - std::chrono::milliseconds(1)); - goto retry; - } else { - msg("mariabackup: TRX_SYS page corrupted.\n"); - error = DB_ERROR; - goto func_exit; - } - } - - /* 0th slot always points to system tablespace. - 1st slot should point to first undotablespace which is minimum. */ - - ut_ad(mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS - + TRX_SYS_RSEG_SLOT_SIZE - + TRX_SYS_RSEG_PAGE_NO + page) - != FIL_NULL); - - space = mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS - + TRX_SYS_RSEG_SLOT_SIZE - + TRX_SYS_RSEG_SPACE + page); - - srv_undo_space_id_start = space; - -func_exit: - aligned_free(page); - ret = os_file_close(file); - ut_a(ret); - - return error; -} - /**************************************************************************** Populates the tablespace memory cache by scanning for and opening data files. @returns DB_SUCCESS or error code.*/ @@ -3923,13 +3840,6 @@ xb_load_tablespaces() } /* Add separate undo tablespaces to fil_system */ - - err = xb_assign_undo_space_start(); - - if (err != DB_SUCCESS) { - return err; - } - err = srv_undo_tablespaces_init(false); if (err != DB_SUCCESS) { diff --git a/mysql-test/suite/innodb/include/have_undo_tablespaces.inc b/mysql-test/suite/innodb/include/have_undo_tablespaces.inc deleted file mode 100644 index 87830a4a5f0..00000000000 --- a/mysql-test/suite/innodb/include/have_undo_tablespaces.inc +++ /dev/null @@ -1,4 +0,0 @@ -if (`select count(*) = 0 from information_schema.global_variables where variable_name like 'innodb_undo_tablespaces' and variable_value >= 2`) -{ - --skip Test requires InnoDB with at-least 2 undo tablespaces. -} diff --git a/mysql-test/suite/innodb/r/log_file.result b/mysql-test/suite/innodb/r/log_file.result index 642ba41d97f..f52f5dd0295 100644 --- a/mysql-test/suite/innodb/r/log_file.result +++ b/mysql-test/suite/innodb/r/log_file.result @@ -184,7 +184,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS -FOUND 1 /InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 1/ in mysqld.1.err +FOUND 1 /Failed to open the undo tablespace/ in mysqld.1.err bak_ib_logfile0 bak_ibdata1 bak_ibdata2 @@ -214,7 +214,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED'); ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS -FOUND 1 /InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 0/ in mysqld.1.err +FOUND 2 /Failed to open the undo tablespace/ in mysqld.1.err bak_ib_logfile0 bak_ibdata1 bak_ibdata2 diff --git a/mysql-test/suite/innodb/r/undo_truncate.result b/mysql-test/suite/innodb/r/undo_truncate.result index 5be1e5c3426..b7729020aca 100644 --- a/mysql-test/suite/innodb/r/undo_truncate.result +++ b/mysql-test/suite/innodb/r/undo_truncate.result @@ -1,3 +1,5 @@ +SET GLOBAL innodb_fast_shutdown=0; +# restart: --innodb_undo_tablespaces=2 SET GLOBAL innodb_undo_log_truncate = 0; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; create table t1(keyc int primary key, c char(100)) engine = innodb; diff --git a/mysql-test/suite/innodb/r/undo_truncate_recover.result b/mysql-test/suite/innodb/r/undo_truncate_recover.result index 909771e6a17..4d75712060a 100644 --- a/mysql-test/suite/innodb/r/undo_truncate_recover.result +++ b/mysql-test/suite/innodb/r/undo_truncate_recover.result @@ -1,3 +1,5 @@ +SET GLOBAL innodb_fast_shutdown=0; +# restart: --innodb_undo_tablespaces=2 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; diff --git a/mysql-test/suite/innodb/r/undo_upgrade.result b/mysql-test/suite/innodb/r/undo_upgrade.result new file mode 100644 index 00000000000..b199f3f7165 --- /dev/null +++ b/mysql-test/suite/innodb/r/undo_upgrade.result @@ -0,0 +1,62 @@ +# +# MDEV-19229 Allow innodb_undo_tablespaces to be changed +# after database creation +# +call mtr.add_suppression("Found .* prepared XA transactions"); +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error."); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +call mtr.add_suppression("InnoDB: Cannot change innodb_undo_tablespaces=.* because previous shutdown was not with innodb_fast_shutdown=0"); +CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB; +connect con_purge,localhost,root,,,; +START TRANSACTION WITH CONSISTENT SNAPSHOT; +connection default; +INSERT INTO t1 VALUES(1); +UPDATE t1 SET f1=100; +# case 1: Undo log left to purge +# restart: --innodb_undo_tablespaces=2 +# Display 4 undo tablespaces +select @@global.innodb_undo_tablespaces; +@@global.innodb_undo_tablespaces +4 +# Should list 4 undo log tablespaces +undo001 +undo002 +undo003 +undo004 +# case 2: XA transaction alone left +InnoDB 0 transactions not purged +XA START 'zombie'; +INSERT INTO t1 VALUES(2); +XA END 'zombie'; +XA PREPARE 'zombie'; +# restart: --innodb_undo_tablespaces=2 +# Display 4 undo tablespaces +select @@global.innodb_undo_tablespaces; +@@global.innodb_undo_tablespaces +4 +# Should list 4 undo log tablespaces +undo001 +undo002 +undo003 +undo004 +XA COMMIT 'zombie'; +# case 3: Successfull innodb_undo_tablespace upgrade +SET GLOBAL innodb_fast_shutdown=0; +# restart: --innodb_undo_tablespaces=2 +# Display 2 undo tablespaces +SELECT @@global.innodb_undo_tablespaces; +@@global.innodb_undo_tablespaces +2 +# Should list 2 undo log tablespaces +undo001 +undo002 +DROP TABLE t1; +InnoDB 0 transactions not purged +# case 4: Reduce the innodb_undo_tablespace to 0 +# restart: --innodb_undo_tablespaces=0 +# Display 0 undo tablespace +SELECT @@global.innodb_undo_tablespaces; +@@global.innodb_undo_tablespaces +0 +# Shouldn't list any undo log tablespaces diff --git a/mysql-test/suite/innodb/r/undo_upgrade_debug.result b/mysql-test/suite/innodb/r/undo_upgrade_debug.result new file mode 100644 index 00000000000..717215f3474 --- /dev/null +++ b/mysql-test/suite/innodb/r/undo_upgrade_debug.result @@ -0,0 +1,43 @@ +# +# MDEV-19229 Allow innodb_undo_tablespaces to be changed +# after database creation +# +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error."); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +set global innodb_fast_shutdown=0; +# case 1: Abort after resetting TRX_SYS page rollback segments +# restart: --innodb_undo_tablespaces=4 --debug_dbug=+d,after_rseg_reset_abort +# restart: --innodb_undo_tablespaces=4 +# Should list 4 undo log tablespaces +undo001 +undo002 +undo003 +undo004 +# case 2: Abort after deleting the old undo tablespaces +# restart: --innodb_undo_tablespaces=2 --debug_dbug=+d,after_deleting_old_undo_abort +# restart: --innodb_undo_tablespaces=2 +# Should list 2 undo log tablespaces +undo001 +undo002 +# case 3: Abort after successfully deleting the old undo tablespace +# restart: --innodb_undo_tablespaces=3 --debug_dbug=+d,after_deleting_old_undo_success +# restart: --innodb_undo_tablespaces=3 +# Should list 3 undo log tablespaces +undo001 +undo002 +undo003 +# case 4: Abort after re-creating new undo tablespaces +# restart: --innodb_undo_tablespaces=4 --debug_dbug=+d,after_reinit_undo_abort +# restart: --innodb_undo_tablespaces=4 +# Should list 4 undo log tablespaces +undo001 +undo002 +undo003 +undo004 +# case 5: Abort after re-creating new undo tablespaces successfully +# restart: --innodb_undo_tablespaces=2 --debug_dbug=+d,after_reinit_undo_success +# restart: --innodb_undo_tablespaces=2 +# Should list 2 undo log tablespaces +undo001 +undo002 diff --git a/mysql-test/suite/innodb/t/log_file.test b/mysql-test/suite/innodb/t/log_file.test index 2484e787973..2f5507b616a 100644 --- a/mysql-test/suite/innodb/t/log_file.test +++ b/mysql-test/suite/innodb/t/log_file.test @@ -164,7 +164,7 @@ let SEARCH_PATTERN=undo tablespace .*undo003.* exists\. Creating system tablespa --source include/start_mysqld.inc eval $check_no_innodb; --source include/shutdown_mysqld.inc -let SEARCH_PATTERN=InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 1; +let SEARCH_PATTERN=Failed to open the undo tablespace; --source include/search_pattern_in_file.inc # clean up & Restore --source ../include/log_file_cleanup.inc @@ -176,7 +176,7 @@ let SEARCH_PATTERN=InnoDB: Expected to open innodb_undo_tablespaces=3 but was ab --source include/start_mysqld.inc eval $check_no_innodb; --source include/shutdown_mysqld.inc -let SEARCH_PATTERN=InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 0; +let SEARCH_PATTERN=Failed to open the undo tablespace; --source include/search_pattern_in_file.inc # clean up & Restore diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test index 19829ce21e7..a5e0a52f798 100644 --- a/mysql-test/suite/innodb/t/undo_truncate.test +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -1,6 +1,5 @@ --source include/have_innodb.inc --source include/innodb_page_size.inc ---source include/have_undo_tablespaces.inc --source include/not_embedded.inc --source include/have_sequence.inc --source include/no_valgrind_without_big.inc @@ -12,6 +11,11 @@ call mtr.add_suppression("InnoDB: Difficult to find free blocks in the buffer po call mtr.add_suppression("InnoDB: Trying to delete tablespace.*pending operations"); --enable_query_log +# Re-create the undo log tablespaces after slow shutdown +SET GLOBAL innodb_fast_shutdown=0; +let $restart_parameters="--innodb_undo_tablespaces=2"; +--source include/restart_mysqld.inc + SET GLOBAL innodb_undo_log_truncate = 0; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; @@ -53,6 +57,7 @@ let $trx_before= `select substr('$trx_before',9)+2`; SET GLOBAL innodb_purge_rseg_truncate_frequency=1; SET GLOBAL innodb_max_purge_lag_wait=0; set global innodb_fast_shutdown=0; +let $restart_parameters=; --source include/restart_mysqld.inc --replace_regex /.*Trx id counter ([0-9]+).*/\1/ let $trx_after= `SHOW ENGINE INNODB STATUS`; diff --git a/mysql-test/suite/innodb/t/undo_truncate_recover.test b/mysql-test/suite/innodb/t/undo_truncate_recover.test index e499ff3dfbe..1b27b0fe6e4 100644 --- a/mysql-test/suite/innodb/t/undo_truncate_recover.test +++ b/mysql-test/suite/innodb/t/undo_truncate_recover.test @@ -8,10 +8,14 @@ --source include/innodb_page_size_small.inc --source include/have_innodb.inc --source include/have_debug.inc ---source include/have_undo_tablespaces.inc # Tests with embedded server do not support restarting --source include/not_embedded.inc +# Re-create the undo log tablespaces after slow shutdown +SET GLOBAL innodb_fast_shutdown=0; +let $restart_parameters="--innodb_undo_tablespaces=2"; +--source include/restart_mysqld.inc + SET GLOBAL innodb_undo_log_truncate = 1; SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; diff --git a/mysql-test/suite/innodb/t/undo_upgrade.opt b/mysql-test/suite/innodb/t/undo_upgrade.opt new file mode 100644 index 00000000000..87bc4c4d7f7 --- /dev/null +++ b/mysql-test/suite/innodb/t/undo_upgrade.opt @@ -0,0 +1,2 @@ +--log-bin=1 +--innodb_undo_tablespaces=4 diff --git a/mysql-test/suite/innodb/t/undo_upgrade.test b/mysql-test/suite/innodb/t/undo_upgrade.test new file mode 100644 index 00000000000..69bd9985eea --- /dev/null +++ b/mysql-test/suite/innodb/t/undo_upgrade.test @@ -0,0 +1,74 @@ +--source include/have_innodb.inc +--source include/innodb_page_size.inc +--source include/not_embedded.inc + +--echo # +--echo # MDEV-19229 Allow innodb_undo_tablespaces to be changed +--echo # after database creation +--echo # +call mtr.add_suppression("Found .* prepared XA transactions"); +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error."); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed."); +call mtr.add_suppression("InnoDB: Cannot change innodb_undo_tablespaces=.* because previous shutdown was not with innodb_fast_shutdown=0"); + +let $MYSQLD_DATADIR= `select @@datadir`; + +CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB; +connect(con_purge,localhost,root,,,); +START TRANSACTION WITH CONSISTENT SNAPSHOT; + +connection default; +INSERT INTO t1 VALUES(1); +UPDATE t1 SET f1=100; + +let $restart_parameters=--innodb_undo_tablespaces=2; +--echo # case 1: Undo log left to purge +--source include/restart_mysqld.inc +--echo # Display 4 undo tablespaces +select @@global.innodb_undo_tablespaces; + +--echo # Should list 4 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +--echo # case 2: XA transaction alone left +--source include/wait_all_purged.inc +XA START 'zombie'; +INSERT INTO t1 VALUES(2); +XA END 'zombie'; +XA PREPARE 'zombie'; + +--source include/restart_mysqld.inc + +--echo # Display 4 undo tablespaces +select @@global.innodb_undo_tablespaces; + +--echo # Should list 4 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +XA COMMIT 'zombie'; + +--echo # case 3: Successfull innodb_undo_tablespace upgrade +SET GLOBAL innodb_fast_shutdown=0; + +let $restart_parameters=--innodb_undo_tablespaces=2; +--source include/restart_mysqld.inc + +--echo # Display 2 undo tablespaces +SELECT @@global.innodb_undo_tablespaces; + +--echo # Should list 2 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +DROP TABLE t1; +--source include/wait_all_purged.inc + +--echo # case 4: Reduce the innodb_undo_tablespace to 0 +let $restart_parameters=--innodb_undo_tablespaces=0; +--source include/restart_mysqld.inc + +--echo # Display 0 undo tablespace +SELECT @@global.innodb_undo_tablespaces; + +--echo # Shouldn't list any undo log tablespaces +list_files $MYSQLD_DATADIR undo*; diff --git a/mysql-test/suite/innodb/t/undo_upgrade_debug.test b/mysql-test/suite/innodb/t/undo_upgrade_debug.test new file mode 100644 index 00000000000..586e3d32c38 --- /dev/null +++ b/mysql-test/suite/innodb/t/undo_upgrade_debug.test @@ -0,0 +1,70 @@ +--source include/have_innodb.inc +--source include/innodb_page_size.inc +--source include/have_debug.inc +--source include/not_embedded.inc + +--echo # +--echo # MDEV-19229 Allow innodb_undo_tablespaces to be changed +--echo # after database creation +--echo # +let $MYSQLD_DATADIR= `select @@datadir`; +call mtr.add_suppression("InnoDB: Plugin initialization aborted"); +call mtr.add_suppression("Plugin 'InnoDB' init function returned error."); +call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed."); + +set global innodb_fast_shutdown=0; + +--echo # case 1: Abort after resetting TRX_SYS page rollback segments +let $restart_parameters=--innodb_undo_tablespaces=4 --debug_dbug="+d,after_rseg_reset_abort"; + +--source include/restart_mysqld.inc + +let $restart_parameters=--innodb_undo_tablespaces=4; +--source include/restart_mysqld.inc + +--echo # Should list 4 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +--echo # case 2: Abort after deleting the old undo tablespaces +let $restart_parameters=--innodb_undo_tablespaces=2 --debug_dbug="+d,after_deleting_old_undo_abort"; + +--source include/restart_mysqld.inc + +let $restart_parameters=--innodb_undo_tablespaces=2; +--source include/restart_mysqld.inc + +--echo # Should list 2 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +--echo # case 3: Abort after successfully deleting the old undo tablespace +let $restart_parameters=--innodb_undo_tablespaces=3 --debug_dbug="+d,after_deleting_old_undo_success"; + +--source include/restart_mysqld.inc + +let $restart_parameters=--innodb_undo_tablespaces=3; +--source include/restart_mysqld.inc + +--echo # Should list 3 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +--echo # case 4: Abort after re-creating new undo tablespaces +let $restart_parameters=--innodb_undo_tablespaces=4 --debug_dbug="+d,after_reinit_undo_abort"; + +--source include/restart_mysqld.inc + +let $restart_parameters=--innodb_undo_tablespaces=4; +--source include/restart_mysqld.inc + +--echo # Should list 4 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; + +--echo # case 5: Abort after re-creating new undo tablespaces successfully +let $restart_parameters=--innodb_undo_tablespaces=2 --debug_dbug="+d,after_reinit_undo_success"; + +--source include/restart_mysqld.inc + +let $restart_parameters=--innodb_undo_tablespaces=2; +--source include/restart_mysqld.inc + +--echo # Should list 2 undo log tablespaces +list_files $MYSQLD_DATADIR undo*; diff --git a/mysql-test/suite/mariabackup/undo_upgrade.result b/mysql-test/suite/mariabackup/undo_upgrade.result new file mode 100644 index 00000000000..dbf7f7b8d67 --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_upgrade.result @@ -0,0 +1,19 @@ +set global innodb_fast_shutdown=0; +# restart: --innodb_undo_tablespaces=2 +CREATE TABLE t1(a varchar(60)) ENGINE INNODB; +start transaction; +INSERT INTO t1 VALUES(1); +# xtrabackup backup +# Restart the server with 4 undo tablespaces +set global innodb_fast_shutdown=0; +# restart: --innodb_undo_tablespaces=4 +# incremental backup should fail +FOUND 1 /--incremental backup is impossible if the server had been restarted with different innodb_undo_tablespaces./ in backup.log +# Take full backup again +# Prepare full backup +# Display 4 undo log files from target directory +undo001 +undo002 +undo003 +undo004 +DROP TABLE t1; diff --git a/mysql-test/suite/mariabackup/undo_upgrade.test b/mysql-test/suite/mariabackup/undo_upgrade.test new file mode 100644 index 00000000000..e14564b476a --- /dev/null +++ b/mysql-test/suite/mariabackup/undo_upgrade.test @@ -0,0 +1,50 @@ +--source include/have_innodb.inc +--source include/innodb_page_size.inc + +let basedir=$MYSQLTEST_VARDIR/tmp/backup; +let incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1; + +set global innodb_fast_shutdown=0; +let $restart_parameters=--innodb_undo_tablespaces=2; +--source include/restart_mysqld.inc + +CREATE TABLE t1(a varchar(60)) ENGINE INNODB; +start transaction; +INSERT INTO t1 VALUES(1); + +--echo # xtrabackup backup +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; +--enable_result_log + +--echo # Restart the server with 4 undo tablespaces +let $restart_parameters=--innodb_undo_tablespaces=4; +set global innodb_fast_shutdown=0; +--source include/restart_mysqld.inc + +let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log; +--echo # incremental backup should fail +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir 2> $backuplog; + +--let SEARCH_PATTERN=--incremental backup is impossible if the server had been restarted with different innodb_undo_tablespaces. +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +remove_file $backuplog; +rmdir $incremental_dir; +rmdir $basedir; + +--echo # Take full backup again +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; +--enable_result_log +--disable_result_log + +echo # Prepare full backup; +exec $XTRABACKUP --prepare --target-dir=$basedir; + +--echo # Display 4 undo log files from target directory +list_files $basedir undo*; + +DROP TABLE t1; +rmdir $basedir; diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h index 44b19aa666b..1372959d184 100644 --- a/storage/innobase/include/srv0start.h +++ b/storage/innobase/include/srv0start.h @@ -33,10 +33,11 @@ Created 10/10/1995 Heikki Tuuri struct dict_table_t; /** Open the configured number of dedicated undo tablespaces. -@param[in] create_new_db whether the database is being initialized +@param[in] create_new_undo whether the undo tablespaces has to be created +@param[in] mtr mini-transaction in case of reinitialize + of undo tablespaces @return DB_SUCCESS or error code */ -dberr_t -srv_undo_tablespaces_init(bool create_new_db); +dberr_t srv_undo_tablespaces_init(bool create_new_undo, mtr_t *mtr= nullptr); /** Start InnoDB. @param[in] create_new_db whether to create a new database diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index 7ad20b0fff0..0b24a2c0335 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -306,7 +306,10 @@ which corresponds to the transaction just being committed. In a replication slave, this updates the master binlog position up to which replication has proceeded. @param[in,out] rseg_header rollback segment header -@param[in] trx committing transaction +@param[in] log_file_name binlog file name +@param[in] offset binlog offset value @param[in,out] mtr mini-transaction */ -void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, const trx_t *trx, +void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, + const char *log_file_name, + ulonglong log_offset, mtr_t *mtr); diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 4d231077b12..ec3a58cbecd 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -855,6 +855,8 @@ class trx_sys_t bool m_initialised; + /** True if there is no undo log to purge or rollback */ + bool undo_log_empty= true; public: /** List of all transactions. */ thread_safe_trx_ilist_t trx_list; @@ -1165,6 +1167,20 @@ public: return count; } + /** Set the undo log empty value */ + void set_undo_empty(bool val) + { + if (undo_log_empty) + undo_log_empty= val; + } + + /** Get the undo log empty value */ + bool is_undo_empty() const { return undo_log_empty; } + + /* Reset the trx_sys page and retain the dblwr information, + system rollback segment header page + @return error code */ + inline dberr_t reset_page(mtr_t *mtr); private: static my_bool find_same_or_older_callback(rw_trx_hash_element_t *element, trx_id_t *id) diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 8e291352d55..90d04ee5cd1 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -97,6 +97,7 @@ Created 2/16/1996 Heikki Tuuri #include "btr0pcur.h" #include "zlib.h" #include "ut0crc32.h" +#include "log.h" /** We are prepared for a situation that we have this many threads waiting for a transactional lock inside InnoDB. srv_start() sets the value. */ @@ -431,11 +432,239 @@ static dberr_t srv_undo_tablespace_create(const char* name) return(err); } -/* Validate the number of undo opened undo tablespace and user given -undo tablespace +inline dberr_t trx_sys_t::reset_page(mtr_t *mtr) +{ + dberr_t err= DB_SUCCESS; + bool dblwr_enabled= true; + buf_block_t *sys_header= buf_page_get_gen( + page_id_t(TRX_SYS_SPACE, TRX_SYS_PAGE_NO), 0, RW_X_LATCH, nullptr, + BUF_GET, mtr, &err); + + if (err) return err; + + dblwr_enabled= + mach_read_from_4(TRX_SYS_DOUBLEWRITE_MAGIC + TRX_SYS_DOUBLEWRITE + + sys_header->page.frame) + == TRX_SYS_DOUBLEWRITE_MAGIC_N; + + char doublewrite[TRX_SYS_DOUBLEWRITE_BLOCK2 + 4]; + memcpy(doublewrite, TRX_SYS_DOUBLEWRITE + sys_header->page.frame, + sizeof doublewrite); + + fsp_init_file_page(fil_system.sys_space, sys_header, mtr); + + mtr->write<2>(*sys_header, FIL_PAGE_TYPE + sys_header->page.frame, + FIL_PAGE_TYPE_TRX_SYS); + + mtr->write<4>(*sys_header, + TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_PAGE_NO + + sys_header->page.frame, FSP_FIRST_RSEG_PAGE_NO); + mtr->memset(sys_header, + TRX_SYS + TRX_SYS_RSEGS + TRX_SYS_RSEG_SLOT_SIZE, + 254 * TRX_SYS_RSEG_SLOT_SIZE, 0xff); + + static_assert(TRX_SYS_RSEG_SLOT_SIZE == 8, ""); + + if (dblwr_enabled) + { + mtr->memcpy( + *sys_header, sys_header->page.frame + TRX_SYS_DOUBLEWRITE, + doublewrite, sizeof doublewrite); + mtr->memmove( + *sys_header, + TRX_SYS_DOUBLEWRITE + FSEG_HEADER_SIZE + TRX_SYS_DOUBLEWRITE_REPEAT, + TRX_SYS_DOUBLEWRITE + FSEG_HEADER_SIZE, 12); + memcpy( + sys_header->page.frame + TRX_SYS_DOUBLEWRITE + + FSEG_HEADER_SIZE + TRX_SYS_DOUBLEWRITE_REPEAT, + sys_header->page.frame + TRX_SYS_DOUBLEWRITE + FSEG_HEADER_SIZE, 12); + } + + trx_rseg_t *rseg= nullptr; + for (ulint rseg_id= 1; rseg_id < TRX_SYS_N_RSEGS; rseg_id++) + { + rseg= &trx_sys.rseg_array[rseg_id]; + rseg->destroy(); + rseg->init(nullptr, FIL_NULL); + } + + return err; +} + +/** Delete the old undo tablespaces present in the undo log directory */ +static dberr_t srv_undo_delete_old_tablespaces() +{ + if (recv_recovery_is_on()) + mysql_mutex_lock(&log_sys.mutex); + /* Delete the old undo tablespaces*/ + for (ulint i= 0; i < srv_undo_tablespaces_open; ++i) + fil_close_tablespace(srv_undo_space_id_start + i); + + if (recv_recovery_is_on()) + mysql_mutex_unlock(&log_sys.mutex); + + DBUG_EXECUTE_IF("after_deleting_old_undo_abort", return DB_ERROR;); + + /* Do checkpoint to get rid of old undo log tablespaces redo logs */ + log_make_checkpoint(); + + DBUG_EXECUTE_IF("after_deleting_old_undo_success", return DB_ERROR;); + + for (ulint i= 0; i < srv_undo_tablespaces_open; ++i) + { + char name[OS_FILE_MAX_PATH]; + snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i + 1); + os_file_delete_if_exists(innodb_data_file_key, name, nullptr); + } + + return DB_SUCCESS; +} + +/** Recreate the undo log tablespaces */ +static dberr_t srv_undo_tablespaces_reinit() +{ + mtr_t mtr; + dberr_t err; + buf_block_t *dict_hdr; + + mtr.start(); + if (srv_undo_tablespaces_open == 0) + { + /* Free the system rollback segment */ + for (ulint i= 1; i < TRX_SYS_N_RSEGS; i++) + { + trx_rseg_t *rseg= &trx_sys.rseg_array[i]; + if (!rseg->space) + continue; + buf_block_t *block= buf_page_get_gen( + rseg->page_id(), 0, RW_X_LATCH, nullptr, BUF_GET, &mtr, &err); + if (err) { mtr.commit(); return err; } + while (!fseg_free_step(TRX_RSEG + TRX_RSEG_FSEG_HEADER + + block->page.frame, &mtr)); + } + } + + /* Reset TRX_SYS page */ + err= trx_sys.reset_page(&mtr); + + if (trx_sys.recovered_binlog_lsn +#ifdef WITH_WSREP + || trx_sys.recovered_wsrep_xid.is_null() +#endif /* WITH_WSREP */ + ) + { + /* Update binlog offset, binlog file name & wsrep xid in + system tablespace rollback segment */ + trx_rseg_t& rseg = trx_sys.rseg_array[0]; + buf_block_t *rseg_hdr= + buf_page_get_gen(rseg.page_id(), 0, RW_X_LATCH, nullptr, BUF_GET, + &mtr, &err); + if (!rseg_hdr) + goto func_exit; + + if (trx_sys.recovered_binlog_lsn > 0) + { + ut_d(const size_t len = strlen(trx_sys.recovered_binlog_filename) + 1); + ut_ad(len > 1); + ut_ad(len <= TRX_RSEG_BINLOG_NAME_LEN); + trx_rseg_update_binlog_offset( + rseg_hdr, trx_sys.recovered_binlog_filename, + trx_sys.recovered_binlog_offset, &mtr); + } + +#ifdef WITH_WSREP + if (!trx_sys.recovered_wsrep_xid.is_null()) + trx_rseg_update_wsrep_checkpoint( + rseg_hdr, &trx_sys.recovered_wsrep_xid, &mtr); +#endif /* WITH_WSREP */ + } + + mtr.commit(); + + DBUG_EXECUTE_IF("after_rseg_reset_abort", + log_write_up_to(mtr.commit_lsn(), true); + err= DB_ERROR;); + + if (err) return err; + + sql_print_information( + "InnoDB: Reinitializing innodb_undo_tablespaces= %u from %u", + srv_undo_tablespaces, srv_undo_tablespaces_open); + + /* Delete the old undo tablespaces */ + err= srv_undo_delete_old_tablespaces(); + if (err) return err; + + mtr.start(); + + dict_hdr= buf_page_get_gen( + page_id_t(DICT_HDR_SPACE, DICT_HDR_PAGE_NO), 0, RW_X_LATCH, + nullptr, BUF_GET, &mtr, &err); + + if (!dict_hdr) + goto func_exit; + + if (srv_undo_tablespaces == 0) + { + srv_undo_space_id_start= 0; + srv_undo_tablespaces_open= 0; + goto func_exit; + } + + /* Assign the new space id for the first undo tablespace */ + srv_undo_space_id_start = mach_read_from_4( + DICT_HDR + DICT_HDR_MAX_SPACE_ID + dict_hdr->page.frame); + + if (srv_undo_space_id_start + srv_undo_tablespaces + > SRV_SPACE_ID_UPPER_BOUND) + { + err= DB_ERROR; + sql_print_error("InnoDB: Running out of tablespace id"); + goto func_exit; + } + + if (fil_assign_new_space_id(&srv_undo_space_id_start)) + mtr.write<4>(*dict_hdr, DICT_HDR + DICT_HDR_MAX_SPACE_ID + + dict_hdr->page.frame, srv_undo_space_id_start); + + /* Re-create the new undo tablespaces */ + err= srv_undo_tablespaces_init(true, &mtr); +func_exit: + mtr.commit(); + + DBUG_EXECUTE_IF("after_reinit_undo_abort", + log_write_up_to(mtr.commit_lsn(), true); + err= DB_ERROR;); + if (err) return err; + + /* Usually, recovery must work no matter when + log_checkpoints are triggered. This is a special case, + because this code is executed as part of InnoDB startup. + Backup requires that the server has been started up, + backup should never observe the log records that + were written in mtr and also srv_undo_tablespaces_init() + initializes the undo tablespace start id based on page0 + content before reading the redo log */ + log_make_checkpoint(); + + DBUG_EXECUTE_IF("after_reinit_undo_success", err= DB_ERROR;); + srv_undo_tablespaces_active= srv_undo_tablespaces; + return err; +} + +/* Reinitialize the undo tablespaces when there is no undo log +left to purge/rollback and validate the number of undo opened +undo tablespace and user given undo tablespace @return DB_SUCCESS if it is valid */ -static dberr_t srv_validate_undo_tablespaces() +static dberr_t srv_undo_tablespaces_reinitialize() { + + /* Re-create the undo tablespaces if it has no undo logs + left to purge/rollback */ + if (srv_undo_tablespaces != srv_undo_tablespaces_open + && trx_sys.is_undo_empty()) + return srv_undo_tablespaces_reinit(); + /* If the user says that there are fewer than what we find we tolerate that discrepancy but not the inverse. Because there could be unused undo tablespaces for future use. */ @@ -449,15 +678,13 @@ static dberr_t srv_validate_undo_tablespaces() return DB_ERROR; } + else if (srv_undo_tablespaces < srv_undo_tablespaces_open) + sql_print_warning("InnoDB: Cannot change innodb_undo_tablespaces=%u " + "because previous shutdown was not with " + "innodb_fast_shutdown=0", srv_undo_tablespaces); else if (srv_undo_tablespaces_open > 0) - { ib::info() << "Opened " << srv_undo_tablespaces_open << " undo tablespaces"; - - if (srv_undo_tablespaces == 0) - ib::warn() << "innodb_undo_tablespaces=0 disables" - " dedicated undo log tablespaces"; - } return DB_SUCCESS; } @@ -643,23 +870,23 @@ srv_check_undo_redo_logs_exists() return(DB_SUCCESS); } -static dberr_t srv_all_undo_tablespaces_open(bool create_new_db, ulint n_undo) +static dberr_t srv_all_undo_tablespaces_open(bool create_new_undo, ulint n_undo) { /* Open all the undo tablespaces that are currently in use. If we fail to open any of these it is a fatal error. The tablespace ids should be contiguous. It is a fatal error because they are required for recovery and are referenced by the UNDO logs (a.k.a RBS). */ - ulint prev_id= create_new_db ? srv_undo_space_id_start - 1 : 0; + ulint prev_id= create_new_undo ? srv_undo_space_id_start - 1 : 0; for (ulint i= 0; i < n_undo; ++i) { char name[OS_FILE_MAX_PATH]; snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i + 1); - ulint space_id= srv_undo_tablespace_open(create_new_db, name, i); + ulint space_id= srv_undo_tablespace_open(create_new_undo, name, i); if (!space_id) { - if (!create_new_db) + if (!create_new_undo) break; ib::error() << "Unable to open create tablespace '" << name << "'."; return DB_ERROR; @@ -686,24 +913,25 @@ static dberr_t srv_all_undo_tablespaces_open(bool create_new_db, ulint n_undo) { char name[OS_FILE_MAX_PATH]; snprintf(name, sizeof name, "%s/undo%03zu", srv_undo_dir, i); - if (!srv_undo_tablespace_open(create_new_db, name, i)) + if (!srv_undo_tablespace_open(create_new_undo, name, i)) break; ++srv_undo_tablespaces_open; } - return srv_validate_undo_tablespaces(); + return DB_SUCCESS; } /** Open the configured number of dedicated undo tablespaces. -@param[in] create_new_db whether the database is being initialized +@param[in] create_new_undo whether the undo tablespaces has to be created +@param[in] mtr mini-transaction in case of reinitialize + of undo tablespaces @return DB_SUCCESS or error code */ -dberr_t -srv_undo_tablespaces_init(bool create_new_db) +dberr_t srv_undo_tablespaces_init(bool create_new_undo, mtr_t *mtr) { srv_undo_tablespaces_open= 0; ut_a(srv_undo_tablespaces <= TRX_SYS_N_RSEGS); - ut_a(!create_new_db || srv_operation == SRV_OPERATION_NORMAL); + ut_a(!create_new_undo || srv_operation == SRV_OPERATION_NORMAL); if (srv_undo_tablespaces == 1) srv_undo_tablespaces= 0; @@ -711,9 +939,8 @@ srv_undo_tablespaces_init(bool create_new_db) /* Create the undo spaces only if we are creating a new instance. We don't allow creating of new undo tablespaces in an existing instance (yet). */ - if (create_new_db) + if (create_new_undo) { - srv_undo_space_id_start= 1; DBUG_EXECUTE_IF("innodb_undo_upgrade", srv_undo_space_id_start= 3;); for (ulint i= 0; i < srv_undo_tablespaces; ++i) @@ -734,11 +961,11 @@ srv_undo_tablespaces_init(bool create_new_db) already exist. */ srv_undo_tablespaces_active= srv_undo_tablespaces; - ulint n_undo= (create_new_db || srv_operation == SRV_OPERATION_BACKUP || + ulint n_undo= (create_new_undo || srv_operation == SRV_OPERATION_BACKUP || srv_operation == SRV_OPERATION_RESTORE_DELTA) ? srv_undo_tablespaces : TRX_SYS_N_RSEGS; - if (dberr_t err= srv_all_undo_tablespaces_open(create_new_db, n_undo)) + if (dberr_t err= srv_all_undo_tablespaces_open(create_new_undo, n_undo)) return err; /* Initialize srv_undo_space_id_start=0 when there are no @@ -746,18 +973,21 @@ srv_undo_tablespaces_init(bool create_new_db) if (srv_undo_tablespaces_open == 0) srv_undo_space_id_start= 0; - if (create_new_db) + if (create_new_undo || mtr) { - mtr_t mtr; + mtr_t *create_mtr= mtr; + if (!create_mtr) create_mtr= new mtr_t(); for (ulint i= 0; i < srv_undo_tablespaces; ++i) { - mtr.start(); + if (!mtr) create_mtr->start(); dberr_t err= fsp_header_init(fil_space_get(srv_undo_space_id_start + i), - SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr); - mtr.commit(); - if (err) - return err; + SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, + create_mtr); + if (!mtr) create_mtr->commit(); + if (err) return err; } + + if (!mtr) delete create_mtr; } return DB_SUCCESS; @@ -1309,6 +1539,8 @@ dberr_t srv_start(bool create_new_db) } return(srv_init_abort(err)); } + + srv_undo_space_id_start= 1; } else { srv_log_file_size = 0; @@ -1475,10 +1707,7 @@ file_checked: /* This must precede recv_sys.apply(true). */ srv_undo_tablespaces_active = trx_rseg_get_n_undo_tablespaces(); - err = srv_validate_undo_tablespaces(); - if (err != DB_SUCCESS) { - return srv_init_abort(err); - } + if (srv_operation != SRV_OPERATION_RESTORE) { dict_sys.load_sys_tables(); } @@ -1512,11 +1741,18 @@ file_checked: } } + err= srv_undo_tablespaces_reinitialize(); + if (err) return srv_init_abort(err); + + if (srv_undo_tablespaces != srv_undo_tablespaces_open) + srv_undo_tablespaces= (ulong) srv_undo_tablespaces_open; + fil_system.space_id_reuse_warned = false; if (!srv_read_only_mode) { const ulint flags = FSP_FLAGS_PAGE_SSIZE(); - for (ulint id = 0; id <= srv_undo_tablespaces; id++) { + for (ulint id = srv_undo_space_id_start; + id <= srv_undo_tablespaces; id++) { if (fil_space_t* space = fil_space_get(id)) { fsp_flags_try_adjust(space, flags); } diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index b5d00d9624f..f7b77260a4c 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -306,7 +306,9 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) /* Update the latest MySQL binlog name and offset info in rollback segment header if MySQL binlogging is on or the database server is a MySQL replication save. */ - trx_rseg_update_binlog_offset(rseg_header, trx, mtr); + trx_rseg_update_binlog_offset( + rseg_header, trx->mysql_log_file_name, + trx->mysql_log_offset, mtr); } /* Add the log as the first in the history list */ diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 760c4e707ce..fbe2bdb36d6 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -30,6 +30,7 @@ Created 3/26/1996 Heikki Tuuri #include "srv0srv.h" #include "trx0purge.h" #include "srv0mon.h" +#include "log.h" #ifdef WITH_WSREP # include <mysql/service_wsrep.h> @@ -369,7 +370,6 @@ void trx_rseg_t::destroy() void trx_rseg_t::init(fil_space_t *space, uint32_t page) { latch.SRW_LOCK_INIT(trx_rseg_latch_key); - ut_ad(!this->space); this->space= space; page_no= page; last_page_no= FIL_NULL; @@ -414,6 +414,7 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, const buf_block_t *rseg_header) { ut_ad(srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN); + bool is_undo_empty= true; for (ulint i= 0; i < TRX_RSEG_N_SLOTS; i++) { @@ -424,11 +425,14 @@ static dberr_t trx_undo_lists_init(trx_rseg_t *rseg, trx_id_t &max_trx_id, max_trx_id); if (!undo) return DB_CORRUPTION; + if (is_undo_empty) + is_undo_empty= !undo->size || undo->state == TRX_UNDO_CACHED; rseg->curr_size+= undo->size; MONITOR_INC(MONITOR_NUM_UNDO_SLOT_USED); } } + trx_sys.set_undo_empty(is_undo_empty); return DB_SUCCESS; } @@ -532,6 +536,7 @@ static dberr_t trx_rseg_mem_restore(trx_rseg_t *rseg, trx_id_t &max_trx_id, purge_sys.purge_queue.push(*rseg); } + trx_sys.set_undo_empty(rseg->history_size == 0); return err; } @@ -592,10 +597,24 @@ dberr_t trx_rseg_array_init() sys, rseg_id); if (page_no != FIL_NULL) { trx_rseg_t& rseg = trx_sys.rseg_array[rseg_id]; - rseg.init(fil_space_get( - trx_sysf_rseg_get_space( - sys, rseg_id)), - page_no); + uint32_t space_id= + trx_sysf_rseg_get_space( + sys, rseg_id); + + fil_space_t *rseg_space = + fil_space_get(space_id); + if (!rseg_space) { + mtr_commit(&mtr); + err = DB_ERROR; + sql_print_error( + "Failed to open the undo " + "tablespace undo%03zu", + (space_id - + srv_undo_space_id_start + 1)); + break; + } + + rseg.init(rseg_space, page_no); ut_ad(rseg.is_persistent()); if ((err = trx_rseg_mem_restore( &rseg, max_trx_id, &mtr)) @@ -685,29 +704,28 @@ which corresponds to the transaction just being committed. In a replication slave, this updates the master binlog position up to which replication has proceeded. @param[in,out] rseg_header rollback segment header -@param[in] trx committing transaction +@param[in] log_file_name binlog file name +@param[in] log_offset binlog file offset @param[in,out] mtr mini-transaction */ -void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, const trx_t *trx, +void trx_rseg_update_binlog_offset(buf_block_t *rseg_header, + const char *log_file_name, + ulonglong log_offset, mtr_t *mtr) { - DBUG_LOG("trx", "trx_mysql_binlog_offset: " << trx->mysql_log_offset); - - const size_t len = strlen(trx->mysql_log_file_name) + 1; + DBUG_PRINT("trx", ("trx_mysql_binlog_offset %llu", log_offset)); + const size_t len= strlen(log_file_name) + 1; + ut_ad(len > 1); - ut_ad(len > 1); + if (UNIV_UNLIKELY(len > TRX_RSEG_BINLOG_NAME_LEN)) + return; - if (UNIV_UNLIKELY(len > TRX_RSEG_BINLOG_NAME_LEN)) { - return; - } - - mtr->write<8,mtr_t::MAYBE_NOP>(*rseg_header, - TRX_RSEG + TRX_RSEG_BINLOG_OFFSET - + rseg_header->page.frame, - trx->mysql_log_offset); + mtr->write<8,mtr_t::MAYBE_NOP>( + *rseg_header, + TRX_RSEG + TRX_RSEG_BINLOG_OFFSET + rseg_header->page.frame, + log_offset); - void* name = TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_header->page.frame; + byte *name= TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_header->page.frame; - if (memcmp(trx->mysql_log_file_name, name, len)) { - mtr->memcpy(*rseg_header, name, trx->mysql_log_file_name, len); - } + if (memcmp(log_file_name, name, len)) + mtr->memcpy(*rseg_header, name, log_file_name, len); } diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 2479e5a4cc1..e98dcef0250 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -325,10 +325,9 @@ bool trx_sys_create_rsegs() /* Increase the number of active undo tablespace in case new rollback segment assigned to new undo tablespace. */ - if (space > srv_undo_tablespaces_active) { + if (space > (srv_undo_space_id_start + + srv_undo_tablespaces_active - 1)) { srv_undo_tablespaces_active++; - - ut_ad(srv_undo_tablespaces_active == space); } } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 111f8fe5f3a..51f333532a5 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -725,6 +725,12 @@ corrupted: return err; } + if (trx_sys.is_undo_empty()) { +func_exit: + purge_sys.clone_oldest_view(); + return DB_SUCCESS; + } + /* Look from the rollback segments if there exist undo logs for transactions. */ const time_t start_time = time(NULL); @@ -785,8 +791,7 @@ corrupted: ib::info() << "Trx id counter is " << trx_sys.get_max_trx_id(); } - purge_sys.clone_oldest_view(); - return DB_SUCCESS; + goto func_exit; } /** Assign a persistent rollback segment in a round-robin fashion, @@ -843,8 +848,7 @@ static trx_rseg_t* trx_assign_rseg_low() ut_ad(rseg->is_persistent()); if (rseg->space != fil_system.sys_space) { - if (rseg->skip_allocation() - || !srv_undo_tablespaces) { + if (rseg->skip_allocation()) { continue; } } else if (const fil_space_t *space = |