Skip to content

Commit baf276e

Browse files
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
1 parent 307d935 commit baf276e

24 files changed

+757
-179
lines changed

extra/mariabackup/write_filt.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ wf_incremental_process(xb_write_filt_ctxt_t *ctxt, ds_file_t *dstfile)
129129
incremental_lsn >= mach_read_from_8(page + FIL_PAGE_LSN))
130130
continue;
131131

132+
/* Check whether TRX_SYS page has been changed */
133+
if (mach_read_from_4(page + FIL_PAGE_SPACE_ID)
134+
== TRX_SYS_SPACE
135+
&& mach_read_from_4(page + FIL_PAGE_OFFSET)
136+
== TRX_SYS_PAGE_NO) {
137+
msg(cursor->thread_n,
138+
"--incremental backup is impossible if "
139+
"the server had been restarted with "
140+
"different innodb_undo_tablespaces.");
141+
return false;
142+
}
143+
132144
/* updated page */
133145
if (cp->npages == page_size / 4) {
134146
/* flush buffer */

extra/mariabackup/xtrabackup.cc

Lines changed: 1 addition & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -3826,89 +3826,6 @@ static dberr_t enumerate_ibd_files(process_single_tablespace_func_t callback)
38263826
return(err);
38273827
}
38283828

3829-
/** Assign srv_undo_space_id_start variable if there are undo tablespace present.
3830-
Read the TRX_SYS page from ibdata1 file and get the minimum space id from
3831-
the first slot rollback segments of TRX_SYS_PAGE_NO.
3832-
@retval DB_ERROR if file open or page read failed.
3833-
@retval DB_SUCCESS if srv_undo_space_id assigned successfully. */
3834-
static dberr_t xb_assign_undo_space_start()
3835-
{
3836-
3837-
pfs_os_file_tfile;
3838-
boolret;
3839-
dberr_terror = DB_SUCCESS;
3840-
uint32_tspace;
3841-
uint32_t fsp_flags;
3842-
intn_retries = 5;
3843-
3844-
if (srv_undo_tablespaces == 0) {
3845-
return error;
3846-
}
3847-
3848-
file = os_file_create(0, srv_sys_space.first_datafile()->filepath(),
3849-
OS_FILE_OPEN, OS_FILE_NORMAL, OS_DATA_FILE, true, &ret);
3850-
3851-
if (!ret) {
3852-
msg("Error opening %s", srv_sys_space.first_datafile()->filepath());
3853-
return DB_ERROR;
3854-
}
3855-
3856-
byte* page = static_cast<byte*>
3857-
(aligned_malloc(srv_page_size, srv_page_size));
3858-
3859-
if (os_file_read(IORequestRead, file, page, 0, srv_page_size)
3860-
!= DB_SUCCESS) {
3861-
msg("Reading first page failed.\n");
3862-
error = DB_ERROR;
3863-
goto func_exit;
3864-
}
3865-
3866-
fsp_flags = mach_read_from_4(
3867-
page + FSP_HEADER_OFFSET + FSP_SPACE_FLAGS);
3868-
retry:
3869-
if (os_file_read(IORequestRead, file, page,
3870-
TRX_SYS_PAGE_NO << srv_page_size_shift,
3871-
srv_page_size) != DB_SUCCESS) {
3872-
msg("Reading TRX_SYS page failed.");
3873-
error = DB_ERROR;
3874-
goto func_exit;
3875-
}
3876-
3877-
/* TRX_SYS page can't be compressed or encrypted. */
3878-
if (buf_page_is_corrupted(false, page, fsp_flags)) {
3879-
if (n_retries--) {
3880-
std::this_thread::sleep_for(
3881-
std::chrono::milliseconds(1));
3882-
goto retry;
3883-
} else {
3884-
msg("mariabackup: TRX_SYS page corrupted.\n");
3885-
error = DB_ERROR;
3886-
goto func_exit;
3887-
}
3888-
}
3889-
3890-
/* 0th slot always points to system tablespace.
3891-
1st slot should point to first undotablespace which is minimum. */
3892-
3893-
ut_ad(mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS
3894-
+ TRX_SYS_RSEG_SLOT_SIZE
3895-
+ TRX_SYS_RSEG_PAGE_NO + page)
3896-
!= FIL_NULL);
3897-
3898-
space = mach_read_from_4(TRX_SYS + TRX_SYS_RSEGS
3899-
+ TRX_SYS_RSEG_SLOT_SIZE
3900-
+ TRX_SYS_RSEG_SPACE + page);
3901-
3902-
srv_undo_space_id_start = space;
3903-
3904-
func_exit:
3905-
aligned_free(page);
3906-
ret = os_file_close(file);
3907-
ut_a(ret);
3908-
3909-
return error;
3910-
}
3911-
39123829
/****************************************************************************
39133830
Populates the tablespace memory cache by scanning for and opening data files.
39143831
@returns DB_SUCCESS or error code.*/
@@ -3946,14 +3863,7 @@ xb_load_tablespaces()
39463863
}
39473864

39483865
/* Add separate undo tablespaces to fil_system */
3949-
3950-
err = xb_assign_undo_space_start();
3951-
3952-
if (err != DB_SUCCESS) {
3953-
return err;
3954-
}
3955-
3956-
err = srv_undo_tablespaces_init(false);
3866+
err = srv_undo_tablespaces_init(false, nullptr);
39573867

39583868
if (err != DB_SUCCESS) {
39593869
return(err);

mysql-test/suite/innodb/include/have_undo_tablespaces.inc

Lines changed: 0 additions & 4 deletions
This file was deleted.

mysql-test/suite/innodb/r/log_file.result

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES
184184
WHERE engine = 'innodb'
185185
AND support IN ('YES', 'DEFAULT', 'ENABLED');
186186
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
187-
FOUND 1 /InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 1/ in mysqld.1.err
187+
FOUND 1 /InnoDB: Failed to open the undo tablespace/ in mysqld.1.err
188188
bak_ib_logfile0
189189
bak_ibdata1
190190
bak_ibdata2
@@ -214,7 +214,7 @@ SELECT * FROM INFORMATION_SCHEMA.ENGINES
214214
WHERE engine = 'innodb'
215215
AND support IN ('YES', 'DEFAULT', 'ENABLED');
216216
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
217-
FOUND 1 /InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 0/ in mysqld.1.err
217+
FOUND 2 /InnoDB: Failed to open the undo tablespace/ in mysqld.1.err
218218
bak_ib_logfile0
219219
bak_ibdata1
220220
bak_ibdata2

mysql-test/suite/innodb/r/undo_truncate.result

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
SET GLOBAL innodb_fast_shutdown=0;
2+
# restart: --innodb_undo_tablespaces=2
13
SET GLOBAL innodb_undo_log_truncate = 0;
24
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
35
create table t1(keyc int primary key, c char(100)) engine = innodb;

mysql-test/suite/innodb/r/undo_truncate_recover.result

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
SET GLOBAL innodb_fast_shutdown=0;
2+
# restart: --innodb_undo_tablespaces=2
13
SET GLOBAL innodb_undo_log_truncate = 1;
24
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
35
create table t1(keyc int primary key, c char(100)) engine = innodb;
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#
2+
# MDEV-19229 Allow innodb_undo_tablespaces to be changed
3+
# after database creation
4+
#
5+
call mtr.add_suppression("Found .* prepared XA transactions");
6+
call mtr.add_suppression("InnoDB: Plugin initialization aborted");
7+
call mtr.add_suppression("Plugin 'InnoDB' init function returned error");
8+
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
9+
call mtr.add_suppression("InnoDB: Cannot change innodb_undo_tablespaces=\\d+ because previous shutdown was not with innodb_fast_shutdown=0");
10+
CREATE TABLE t1(f1 INT NOT NULL)ENGINE=InnoDB;
11+
connect con_purge,localhost,root,,,;
12+
START TRANSACTION WITH CONSISTENT SNAPSHOT;
13+
connection default;
14+
INSERT INTO t1 VALUES(1);
15+
UPDATE t1 SET f1=100;
16+
# case 1: Undo log left to purge
17+
# restart: --innodb_undo_tablespaces=2
18+
# Display 4 undo tablespaces
19+
select @@global.innodb_undo_tablespaces;
20+
@@global.innodb_undo_tablespaces
21+
4
22+
# Should list 4 undo log tablespaces
23+
undo001
24+
undo002
25+
undo003
26+
undo004
27+
# case 2: XA transaction alone left
28+
InnoDB 0 transactions not purged
29+
XA START 'zombie';
30+
INSERT INTO t1 VALUES(2);
31+
XA END 'zombie';
32+
XA PREPARE 'zombie';
33+
# restart: --innodb_undo_tablespaces=2
34+
# Display 4 undo tablespaces
35+
select @@global.innodb_undo_tablespaces;
36+
@@global.innodb_undo_tablespaces
37+
4
38+
# Should list 4 undo log tablespaces
39+
undo001
40+
undo002
41+
undo003
42+
undo004
43+
XA COMMIT 'zombie';
44+
# case 3: Successful innodb_undo_tablespace upgrade
45+
SET GLOBAL innodb_fast_shutdown=0;
46+
# restart: --innodb_undo_tablespaces=2
47+
# Display 2 undo tablespaces
48+
SELECT @@global.innodb_undo_tablespaces;
49+
@@global.innodb_undo_tablespaces
50+
2
51+
# Should list 2 undo log tablespaces
52+
undo001
53+
undo002
54+
DROP TABLE t1;
55+
InnoDB 0 transactions not purged
56+
# case 4: Reduce the innodb_undo_tablespace to 0
57+
# restart: --innodb_undo_tablespaces=0
58+
# Display 0 undo tablespace
59+
SELECT @@global.innodb_undo_tablespaces;
60+
@@global.innodb_undo_tablespaces
61+
0
62+
# Shouldn't list any undo log tablespaces
63+
# case 5: Change undo tablespace when force_recovery < 5
64+
# restart: --innodb_undo_tablespaces=2 --innodb_force_recovery=4
65+
# Display 2 undo tablespace
66+
SELECT @@global.innodb_undo_tablespaces;
67+
@@global.innodb_undo_tablespaces
68+
2
69+
# Should list 2 undo log tablespaces
70+
undo001
71+
undo002
72+
# case 6: Fail to change undo tablespace when force_recovery > 4
73+
# restart: --innodb_undo_tablespaces=4 --innodb_force_recovery=5
74+
# Display 2 undo tablespace
75+
SELECT @@global.innodb_undo_tablespaces;
76+
@@global.innodb_undo_tablespaces
77+
2
78+
# Should list 2 undo log tablespaces, not 4
79+
undo001
80+
undo002
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#
2+
# MDEV-19229 Allow innodb_undo_tablespaces to be changed
3+
# after database creation
4+
#
5+
call mtr.add_suppression("InnoDB: Plugin initialization aborted");
6+
call mtr.add_suppression("Plugin 'InnoDB' init function returned error");
7+
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
8+
set global innodb_fast_shutdown=0;
9+
# case 1: Abort after resetting TRX_SYS page rollback segments
10+
# restart: --innodb_undo_tablespaces=4 --debug_dbug=+d,after_rseg_reset_abort
11+
# restart: --innodb_undo_tablespaces=4
12+
# Should list 4 undo log tablespaces
13+
undo001
14+
undo002
15+
undo003
16+
undo004
17+
# case 2: Abort after deleting the old undo tablespaces
18+
# restart: --innodb_undo_tablespaces=2 --debug_dbug=+d,after_deleting_old_undo_abort
19+
# restart: --innodb_undo_tablespaces=2
20+
# Should list 2 undo log tablespaces
21+
undo001
22+
undo002
23+
# case 3: Abort after successfully deleting the old undo tablespace
24+
# restart: --innodb_undo_tablespaces=3 --debug_dbug=+d,after_deleting_old_undo_success
25+
# restart: --innodb_undo_tablespaces=3
26+
# Should list 3 undo log tablespaces
27+
undo001
28+
undo002
29+
undo003
30+
# case 4: Abort after re-creating new undo tablespaces
31+
# restart: --innodb_undo_tablespaces=4 --debug_dbug=+d,after_reinit_undo_abort
32+
# restart: --innodb_undo_tablespaces=4
33+
# Should list 4 undo log tablespaces
34+
undo001
35+
undo002
36+
undo003
37+
undo004
38+
# case 5: Abort after re-creating new undo tablespaces successfully
39+
# restart: --innodb_undo_tablespaces=2 --debug_dbug=+d,after_reinit_undo_success
40+
# restart: --innodb_undo_tablespaces=2
41+
# Should list 2 undo log tablespaces
42+
undo001
43+
undo002

mysql-test/suite/innodb/t/log_file.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ let SEARCH_PATTERN=undo tablespace .*undo003.* exists\. Creating system tablespa
164164
--source include/start_mysqld.inc
165165
eval $check_no_innodb;
166166
--source include/shutdown_mysqld.inc
167-
let SEARCH_PATTERN=InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 1;
167+
let SEARCH_PATTERN=InnoDB: Failed to open the undo tablespace;
168168
--source include/search_pattern_in_file.inc
169169
# clean up & Restore
170170
--source ../include/log_file_cleanup.inc
@@ -176,7 +176,7 @@ let SEARCH_PATTERN=InnoDB: Expected to open innodb_undo_tablespaces=3 but was ab
176176
--source include/start_mysqld.inc
177177
eval $check_no_innodb;
178178
--source include/shutdown_mysqld.inc
179-
let SEARCH_PATTERN=InnoDB: Expected to open innodb_undo_tablespaces=3 but was able to find only 0;
179+
let SEARCH_PATTERN=InnoDB: Failed to open the undo tablespace;
180180
--source include/search_pattern_in_file.inc
181181

182182
# clean up & Restore

mysql-test/suite/innodb/t/undo_truncate.test

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
--source include/have_innodb.inc
22
--source include/innodb_page_size.inc
3-
--source include/have_undo_tablespaces.inc
43
--source include/not_embedded.inc
54
--source include/have_sequence.inc
65
--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
1211
call mtr.add_suppression("InnoDB: Trying to delete tablespace.*pending operations");
1312
--enable_query_log
1413

14+
# Re-create the undo log tablespaces after slow shutdown
15+
SET GLOBAL innodb_fast_shutdown=0;
16+
let $restart_parameters="--innodb_undo_tablespaces=2";
17+
--source include/restart_mysqld.inc
18+
1519
SET GLOBAL innodb_undo_log_truncate = 0;
1620
SET GLOBAL innodb_purge_rseg_truncate_frequency = 1;
1721

@@ -53,6 +57,7 @@ let $trx_before= `select substr('$trx_before',9)+2`;
5357
SET GLOBAL innodb_purge_rseg_truncate_frequency=1;
5458
SET GLOBAL innodb_max_purge_lag_wait=0;
5559
set global innodb_fast_shutdown=0;
60+
let $restart_parameters=;
5661
--source include/restart_mysqld.inc
5762
--replace_regex /.*Trx id counter ([0-9]+).*/\1/
5863
let $trx_after= `SHOW ENGINE INNODB STATUS`;

0 commit comments

Comments
 (0)