Bug #108314 Modifications of uncommitted transactions are seen by other sessions
Submitted: 29 Aug 2022 7:55 Modified: 1 Sep 2022 7:31
Reporter: Zhang JiYang Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S1 (Critical)
Version:8.0.30 OS:Any
Assigned to: CPU Architecture:Any

[29 Aug 2022 7:55] Zhang JiYang
Description:
If the database run as --skip-log-bin, the steps to commit in innodb are as follows:
1. The mtr of modifying undo log header commits. 
2. Erase the trx_id from rw_trx_ids
3. Wait for the redo sync.

If there is a session run a query after step-2 and before step-3, then it can see the modification of the transaction that hasn't been really committed.

How to repeat:
1. Inject a part of the code and compile it in debug mode.

diff --git a/storage/innobase/log/log0write.cc b/storage/innobase/log/log0write.cc
index 74cbcbe1b03..bf451b71a26 100644
--- a/storage/innobase/log/log0write.cc
+++ b/storage/innobase/log/log0write.cc
@@ -1786,6 +1786,12 @@ static dberr_t log_write_buffer(log_t &log, byte *buffer, size_t buffer_size,

   srv_stats.os_log_pending_writes.inc();

+  DBUG_EXECUTE_IF("stop_write_blocks_when_write_redo", {
+    std::this_thread::sleep_for(
+        std::chrono::seconds(2));
+    DBUG_SUICIDE();
+  });
+
   /* Now, we know, that we are going to write completed
   blocks only (originally or copied and completed). */
   const dberr_t err = write_blocks(log, write_buf, write_size, real_offset);

2. Write a MTR test-cases, which might called as trx_text.test
connect (con1,localhost,root,,);

connection default;
create table t1 (id int primary key);

begin;
insert into t1 values (1);

SET GLOBAL DEBUG="+d, stop_write_blocks_when_write_redo";
--send commit

connection con1;
sleep 1;
let $cnt1 = `select count(1) from test.t1`;

--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect

connection default;
--error 2013
--reap

--enable_reconnect
--source include/wait_until_connected_again.inc

let $cnt2 = `select count(1) from test.t1`;

--let $assert_text= Assert value should not be same
--let $assert_cond = ($cnt1 = $cnt2)
--source include/assert.inc

3. Write a configure file for the testcase, which might be called mysql-test/t/trx_test-master.opt:
--skip-log-bin

4. Run the testcase, and the it will fail.
[1 Sep 2022 7:31] MySQL Verification Team
Hello zanye zjy,

Thank you for the report and test case.

regards,
Umesh