The transaction submission process of mysql source code interpretation--Part 2

Keyword: The transaction submission process of mysql source code interpretation - the second article In the


previous article, I introduced the general process of transaction submission when binlog is closed. The reason why binlog is closed is because the transaction submission process will become a two-stage submission after binlog is turned on. The two-stage submission here does not involve distributed transactions. Of course, mysql calls it internal xa transactions (Distributed Transactions), which corresponds to it. There is also an external xa transaction. I understand that internal xa transactions mainly exist within mysql to ensure the consistency of data between binlog and redo log, which is also determined by its architecture (binlog is at the mysql layer, and redo log is at the storage engine layer); while the external xa Transactions refer to supporting multi-instance distributed transactions, which are truly distributed transactions. Since it is an xa transaction, it must involve two-phase commit. For internal xa, there are also two phases of commit. The following will explain the two-phase commit process of the internal xa in detail in combination with the source code, and how mysql recovers to ensure transaction consistency after mysqld crashes under various circumstances.

Test environment:
OS: windows
DB: mysql 5.6.12
engine: innodb

configuration file parameters:
log-bin=D:\chuck\mysql\log\5-6-12\mysql-bin
binlog_format=ROW
set autocommit=0;
sync_binlog =1;
innodb_flush_log_at_trx_commit=1;
innodb_support_xa=1;

test preconditions:
create table tt(col1 int, col2 varchar(100));

Test statement:
insert into tt values(1, 'abcdef');
commit;

     After turning on the binlog option, when the transaction commit command is executed, it will enter the two-phase commit mode. Two-phase commit is divided into two phases: prepare phase and commit. The process is as follows: There are two important parameters involved: innodb_flush_log_at_trx_commit and sync_binlog. The parameters can be set to different values. For details, please refer to the help manual of mysql. What I set here is the double-one mode (innodb_flush_log_at_trx_commit=1, sync_binlog=1). The difference between different modes is that the frequency of calling write to write files and calling fsync to disk are different. The consequence is that after mysqld or os crash, it is not strict. settings may lose transactional updates. Double one mode is the strictest mode, in this setting, the single machine will not lose transaction updates under any circumstances.
Prepare stage:
    1. Set undo state=TRX_UNDO_PREPARED; //trx_undo_set_state_at_prepare calls
    2. Brush the redo log generated by transaction update; [The redo log generated in step 1 will also be flushed]
   
Commit stage:
   1. Write the binlog generated by the transaction to the file , flush to disk;
   2. Set the state of the undo page to TRX_UNDO_TO_FREE or TRX_UNDO_TO_PURGE; // trx_undo_set_state_at_finish call
   3. Record the binlog offset corresponding to the transaction and write it into the system tablespace; //trx_sys_update_mysql_binlog_offset call
   
    The following part is the source code call part that I abstracted. You can set breakpoints in key functions by single-step debugging to detail Learn about the process.
===========
prepare phase
===========
MYSQL_BIN_LOG::prepare
    ha_prepare_low
    {
engine:
binlog_prepare
innobase_xa_prepare
mysql:
trx_prepare_for_mysql
{
                1.trx_undo_set_state_at_prepare //Set the mark of the undo segment to TRX_UNDO_PREPARED
                2. Set the transaction status to TRX_STATE_PREPARED 3.
                trx_flush_log_if_needed // flush the generated redolog to disk
            }
     }
    
============
Commit stage
============
MYSQL_BIN_LOG::commit
    ordered_commit
   {
1.FLUSH_STAGE
        flush_cache_to_file // flush binlog

2.SYNC_STAGE
        sync_binlog_file //Call fsync() to sync the file to disk.

3.COMMIT_STAGE
        ha_commit_low
        {
            binlog_commit
            innobase_commit  
                trx_commit(trx)
                {
                    trx_write_serialisation_history(trx, mtr); //Update the binlog site, set the undo state
                    trx_commit_in_memory(trx, lsn); //Release lock resources, clear the savepoint list, and clear the rollback segment
                }       
        }
    }

      mysqld may crash under any circumstances, and os may also have problems. In addition, if the machine is powered off, mysqld will also hang up. But even so, mysql can still guarantee the consistency of the database. Next, I will combine the above process to analyze how the two-phase commit guarantees this. Several common scenarios are given below:
1. prepare stage, before redo log is dropped, mysqld crash
2. prepare stage, after redo log is dropped, before binlog is dropped, mysqld crash
3.commit stage, after binlog is dropped, mysqld crash
      For the first case, since the redo is not placed on the disk, there is no doubt that the update of the transaction must not be written to the disk, and the consistency of the database is affected; for the second case, the redo log writing is completed at this time, but the binlog It has not been written yet, and the transaction is in the TRX_STATE_PREPARED state. Is this committed or rolled back? For the third case, at this time, both the redo log and binlog have been placed on the disk, but the undo status has not been updated. This situation should also be submitted, because the redo log and binlog are already consistent, of course, this is just my assumption, you need to go through the source code logic to verify.
     The execution logic and key source code of mysqld after abnormal restart are given below. For the third case, we can collect the binlog event of the uncommitted transaction, so it needs to be submitted, which is consistent with our assumption; for the second case, since the binlog is not written, it is necessary to perform a rollback operation to ensure the consistency of the database sex.

After an abnormal restart, how to judge whether the transaction should be committed or rolled back
1. Read the binlog log to get the events that were not committed when the crash occurred; //info->commit_list contains this element
2. If it exists, the corresponding transaction must be committed; otherwise, it needs to be rollback.

The source code for judging transaction commit or rollback is as follows:




     The basic process of two-phase commit is discussed above, and how mysql restarts and restores to ensure the consistency of binlog and data after the server crashes abnormally. In short, for an abnormal xa transaction, if the binlog has been dropped, the transaction should be committed; if the binlog has not been dropped, the transaction should be rolled back. Since this piece involves a lot of source code, I haven't read all the source code. If there is anything wrong, please correct me.

//After abnormal restart, rollback process
innobase_rollback_by_xid
    rollback_by_xid
trx_rollback_resurrected
    trx_rollback_active
        row_undo
        {
            //Get undo record from rollback page
            //Analyze undo record type
            if (insert)
                row_undo_ins
            else
                row_undo_mod
        }

//After abnormal restart, submit process
commit_by_xid
    trx_commit_for_mysql

// Write binlog interface
handler.cc:binlog_log_row
sql/binlog.cc:commit
mysys/my_sync:my_sync
sql/binlog.cc:sync_binlog_file
handler/ha_innodb.cc:innobase_xa_prepare

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326069653&siteId=291194637