Details
-
Bug
-
Status: Closed (View Workflow)
-
Critical
-
Resolution: Fixed
-
10.5, 10.6, 10.3.5, 10.3(EOL), 10.4(EOL), 10.7(EOL)
Description
This was first noticed by krunalbauskar: innodb_undo_log_truncate may cause the sequence of DB_TRX_ID to be reset or rolled back.
Ever since MDEV-15158, we no longer write that sequence in the TRX_SYS page, only in the undo log header pages. But, undo log truncation fails to preserve the transaction identifier when rebuilding the undo log header pages. This can be reproduced with the following patch to the current 10.3:
diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test
|
index bc2e6a3a119..9ef0f5b52c6 100644
|
--- a/mysql-test/suite/innodb/t/undo_truncate.test
|
+++ b/mysql-test/suite/innodb/t/undo_truncate.test
|
@@ -48,21 +48,14 @@ commit; disconnect con1;
|
connection con2; commit; disconnect con2;
|
|
connection default;
|
-drop table t1, t2;
|
|
---source include/wait_all_purged.inc
|
+--replace_regex /.*Trx id counter ([0-9]+).*/\1/
|
+SHOW ENGINE INNODB STATUS;
|
|
-# 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;
|
-}
|
+set global innodb_fast_shutdown=0;
|
+--source include/restart_mysqld.inc
|
+--replace_regex /.*Trx id counter ([0-9]+).*/\1/
|
+SHOW ENGINE INNODB STATUS;
|
|
-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;
|
+check table t1, t2;
|
+drop table t1, t2;
|
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
|
index 9d19a14cb66..a5127400dfb 100644
|
--- a/storage/innobase/srv/srv0srv.cc
|
+++ b/storage/innobase/srv/srv0srv.cc
|
@@ -2640,6 +2640,7 @@ static ulint srv_do_purge(ulint* n_total_purged
|
n_pages_purged = trx_purge(
|
n_use_threads,
|
(++count % rseg_truncate_frequency) == 0
|
+ || !srv_fast_shutdown
|
#ifdef UNIV_DEBUG
|
, slot
|
#endif |
The output indicates that the transaction identifier is moving backwards across the server restart:
10.3 b46cf33ab8ce869af0f51c35026965d237d722c7 |
innodb.undo_truncate '2,4k,innodb' [ fail ]
|
Test ended at 2021-09-24 10:10:33
|
|
CURRENT_TEST: innodb.undo_truncate
|
--- /mariadb/10.3/mysql-test/suite/innodb/r/undo_truncate.result 2021-09-22 17:42:10.012874162 +0300
|
+++ /mariadb/10.3/mysql-test/suite/innodb/r/undo_truncate.reject 2021-09-24 10:10:32.937465462 +0300
|
@@ -35,8 +35,25 @@
|
commit;
|
disconnect con2;
|
connection default;
|
+SHOW ENGINE INNODB STATUS;
|
+Type Name Status
|
+InnoDB 41
|
+set global innodb_fast_shutdown=0;
|
+SHOW ENGINE INNODB STATUS;
|
+Type Name Status
|
+InnoDB 38
|
…
|
The fix is to write the latest transaction ID value to the rebuilt undo log header page, so that it can be found there on server restart:
diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc
|
--- a/storage/innobase/trx/trx0rseg.cc
|
+++ b/storage/innobase/trx/trx0rseg.cc
|
@@ -286,6 +286,7 @@ void trx_rseg_format_upgrade(trx_rsegf_t* rseg_header, mtr_t* mtr)
|
/** Create a rollback segment header.
|
@param[in,out] space system, undo, or temporary tablespace
|
@param[in] rseg_id rollback segment identifier
|
+@param[in] max_trx_id new value of TRX_RSEG_MAX_TRX_ID
|
@param[in,out] sys_header the TRX_SYS page (NULL for temporary rseg)
|
@param[in,out] mtr mini-transaction
|
@return the created rollback segment
|
@@ -294,6 +295,7 @@ buf_block_t*
|
trx_rseg_header_create(
|
fil_space_t* space,
|
ulint rseg_id,
|
+ trx_id_t max_trx_id,
|
buf_block_t* sys_header,
|
mtr_t* mtr)
|
{
|
@@ -319,6 +321,12 @@ trx_rseg_header_create(
|
|
mlog_write_ulint(TRX_RSEG + TRX_RSEG_HISTORY_SIZE + block->frame, 0,
|
MLOG_4BYTES, mtr);
|
+
|
+ if (max_trx_id) {
|
+ mlog_write_ull(TRX_RSEG + TRX_RSEG_MAX_TRX_ID + block->frame,
|
+ max_trx_id, mtr);
|
+ }
|
+
|
flst_init(TRX_RSEG + TRX_RSEG_HISTORY + block->frame, mtr);
|
trx_rsegf_t* rsegf = TRX_RSEG + block->frame;
|
|
(snip many changes to pass the parameter as 0)
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
|
index d300e3b54e3..208f400c8a3 100644
|
--- a/storage/innobase/trx/trx0purge.cc
|
+++ b/storage/innobase/trx/trx0purge.cc
|
@@ -977,7 +977,8 @@ trx_purge_initiate_truncate(
|
for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) {
|
trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i);
|
buf_block_t* rblock = trx_rseg_header_create(
|
- space, rseg->id, sys_header, &mtr);
|
+ space, rseg->id, trx_sys.get_max_trx_id(),
|
+ sys_header, &mtr);
|
ut_ad(rblock);
|
rseg->page_no = rblock ? rblock->page.id.page_no() : FIL_NULL;
|
|
With that fix and the above instrumentation, the transaction identifier would be preserved across restart:
+SHOW ENGINE INNODB STATUS;
|
+Type Name Status
|
+InnoDB 41
|
+set global innodb_fast_shutdown=0;
|
+SHOW ENGINE INNODB STATUS;
|
+Type Name Status
|
+InnoDB 43
|
Attachments
Issue Links
- is caused by
-
MDEV-15158 On commit, do not write to the TRX_SYS page
- Closed
- is part of
-
MDEV-26450 Corruption due to innodb_undo_log_truncate
- Closed
- relates to
-
MDEV-26755 innodb.undo_truncate: ilink::assert_linked(): Assertion `prev != 0 && next != 0' failed.
- Closed