MDEV-19229 Allow innodb_undo_tablespaces to be changed after database creation

trx_sys_t::undo_log_nonempty: Set to true if there are undo logs
to rollback and purge.

The algorithm for re-creating the undo tablespace when
trx_sys_t::undo_log_nonempty is disabled:

1) trx_sys_t::reset_page(): Reset the TRX_SYS page and assign all
rollback segment slots from 1..127 to FIL_NULL

2) Free the rollback segment header page of system tablespace
for the slots 1..127

3) Update the binlog and WSREP information in system tablespace
rollback segment header
Step (1), (2) and Step (3) should happen atomically within a
single mini-transaction.

4) srv_undo_delete_old_tablespaces(): Delete the old undo tablespaces
present in the undo log directory

5) Make checkpoint to get rid of old undo log tablespaces redo logs

6) Assign new start space id for the undo log tablespaces

7) Re-create the specified undo log tablespaces. InnoDB uses same
mtr for this one and step (6)

8) Make checkpoint again, so that server or mariabackup
can read the undo log tablespace page0 before applying
the redo logs

srv_undo_tablespaces_reinit(): Recreate the undo log tablespaces.
It does reset trx_sys page, delete the old undo tablespaces,
update the binlog offset, write set replication checkpoint
in system rollback segment page

trx_rseg_update_binlog_offset(): Added 2 new parameters to pass
binlog file name and binlog offset

trx_rseg_array_init(): Return error if the rollback segment
slot points to non-existent tablespace

srv_undo_tablespaces_init(): Added new parameter mtr
to initialize all undo tablespaces

trx_assign_rseg_low(): Allow the transaction to use the rollback
segment slots(1..127) even if InnoDB failed to change to the
requested innodb_undo_tablespaces=0

srv_start(): Override the user specified value of
innodb_undo_tablespaces variable with already existing actual
undo tablespaces

wf_incremental_process(): Detects whether TRX_SYS page has been
modified since last backup. If it is then incremental backup
fails and throws the information about taking full backup again

xb_assign_undo_space_start(): Removed the function. Because
undo001 has first undo space id value in page0

Added test case to test the scenario during startup and mariabackup
incremental process too.

Reviewed-by : Marko Mäkelä
Tested-by : Matthias Leich
parent 307d935e
......@@ -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 */
......
......@@ -3826,89 +3826,6 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
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;
uint32_t space;
uint32_t fsp_flags;
int n_retries = 5;
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.*/
......@@ -3946,14 +3863,7 @@ 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);
err = srv_undo_tablespaces_init(false, nullptr);
if (err != DB_SUCCESS) {
return(err);
......
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.
}
......@@ -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 /InnoDB: 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 /InnoDB: Failed to open the undo tablespace/ in mysqld.1.err
bak_ib_logfile0
bak_ibdata1
bak_ibdata2
......
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;
......
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;
......
#
# 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=\\d+ 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: Successful 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
# case 5: Change undo tablespace when force_recovery < 5
# restart: --innodb_undo_tablespaces=2 --innodb_force_recovery=4
# Display 2 undo tablespace
SELECT @@global.innodb_undo_tablespaces;
@@global.innodb_undo_tablespaces
2
# Should list 2 undo log tablespaces
undo001
undo002
# case 6: Fail to change undo tablespace when force_recovery > 4
# restart: --innodb_undo_tablespaces=4 --innodb_force_recovery=5
# Display 2 undo tablespace
SELECT @@global.innodb_undo_tablespaces;
@@global.innodb_undo_tablespaces
2
# Should list 2 undo log tablespaces, not 4
undo001
undo002
#
# 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
......@@ -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=InnoDB: 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=InnoDB: Failed to open the undo tablespace;
--source include/search_pattern_in_file.inc
# clean up & Restore
......
--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`;
......
......@@ -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;
......
--log-bin=1
--innodb_undo_tablespaces=4
--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=\\d+ 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: Successful 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*;
--echo # case 5: Change undo tablespace when force_recovery < 5
let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_force_recovery=4;
--source include/restart_mysqld.inc
--echo # Display 2 undo tablespace
SELECT @@global.innodb_undo_tablespaces;
--echo # Should list 2 undo log tablespaces
list_files $MYSQLD_DATADIR undo*;
--echo # case 6: Fail to change undo tablespace when force_recovery > 4
let $restart_parameters=--innodb_undo_tablespaces=4 --innodb_force_recovery=5;
--source include/restart_mysqld.inc
--echo # Display 2 undo tablespace
SELECT @@global.innodb_undo_tablespaces;
--echo # Should list 2 undo log tablespaces, not 4
list_files $MYSQLD_DATADIR undo*;
--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*;
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;
--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;
......@@ -33,10 +33,10 @@ 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,out] mtr mini-transaction
@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);
/** Start InnoDB.
@param[in] create_new_db whether to create a new database
......
......@@ -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] log_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);
......@@ -855,6 +855,8 @@ class trx_sys_t
bool m_initialised;
/** False if there is no undo log to purge or rollback */
bool undo_log_nonempty;
public:
/** List of all transactions. */
thread_safe_trx_ilist_t trx_list;
......@@ -1165,6 +1167,20 @@ class trx_sys_t
return count;
}
/** Set the undo log empty value */
void set_undo_non_empty(bool val)
{
if (!undo_log_nonempty)
undo_log_nonempty= val;
}
/** Get the undo log empty value */
bool is_undo_empty() const { return !undo_log_nonempty; }
/* 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)
......
This diff is collapsed.
......@@ -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 */
......
......@@ -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,7 @@ 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);
ut_ad(!this->space || this->space != space);
this->space= space;
page_no= page;
last_page_no= FIL_NULL;
......@@ -414,6 +415,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 +426,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_non_empty(!is_undo_empty);
return DB_SUCCESS;
}
......@@ -532,6 +537,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_non_empty(rseg->history_size > 0);
return err;
}
......@@ -592,10 +598,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();
err = DB_ERROR;
sql_print_error(
"InnoDB: Failed to open the undo "
"tablespace undo%03" PRIu32,
(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 +705,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);
DBUG_PRINT("trx", ("trx_mysql_binlog_offset %llu", log_offset));
const size_t len= strlen(log_file_name) + 1;
ut_ad(len > 1);
const size_t len = strlen(trx->mysql_log_file_name) + 1;
if (UNIV_UNLIKELY(len > TRX_RSEG_BINLOG_NAME_LEN))
return;
ut_ad(len > 1);
mtr->write<8,mtr_t::MAYBE_NOP>(
*rseg_header,
TRX_RSEG + TRX_RSEG_BINLOG_OFFSET + rseg_header->page.frame,
log_offset);
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);
byte *name= TRX_RSEG + TRX_RSEG_BINLOG_NAME + rseg_header->page.frame;
void* 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);
}
......@@ -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);
}
}
......
......@@ -725,6 +725,12 @@ dberr_t trx_lists_init_at_db_start()
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 @@ dberr_t trx_lists_init_at_db_start()
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 =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment