[MySQL源码]:事务提交之InnoDB Prepare

MySQL 5.6 InnoDB Prepare流程如下

innobase_xa_prepare  // InnoDB Prepare 
    trx_prepare_for_mysql   //事务层Prepare
        {
        trx->op_info = "preparing"; //设置事物的操作状态为preparing
        trx_prepare(trx);  ////事物Prepare
            trx_undo_set_state_at_prepare()  //设置undo状态为Prepare
                undo->state = TRX_UNDO_PREPARED;
                undo->xid   = trx->xid;
            trx->state = TRX_STATE_PREPARED  //设置事物状态
            trx_flush_log_if_needed(lsn, trx);  //刷新redo日志
                {
                trx->op_info = "flushing log";
                trx_flush_log_if_needed_low(lsn); //刷新到指定lsn的redo
                    log_write_up_to()    //实际刷新redo的函数
                trx->op_info = "";
                }
        trx->op_info = "";  //设置事物的操作状态为""
        }

innodb_flush_log_at_trx_commit参数指定了InnoDB redo刷新的策略,在trx_flush_log_if_needed_low函数中体现
0:表示不刷新redo,啥也不干
1:刷新redo且刷新到日志到磁盘
2:刷新redo但落盘由操作系统控制

trx_flush_log_if_needed_low(
/*========================*/
    lsn_t    lsn)    /*!< in: lsn up to which logs are to be
            flushed. */
{
    switch (srv_flush_log_at_trx_commit) {
    case 0:      //参数设置为0时不做任何操作
        /* Do nothing */
        break;
    case 1:      //参数为1时,flush redo且写到磁盘
        /* Write the log and optionally flush it to disk */
        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP,
                srv_unix_file_flush_method != SRV_UNIX_NOSYNC);
        break;
    case 2:      //参数为2时,flush redo,但不写到磁盘盘
        /* Write the log but do not flush it to disk */
        log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, FALSE);

        break;
    default:
        ut_error;
    }
}      

 相较于5.6 InnoDB Prepare,5.7做了优化,在Innodb Prepare阶段不会再flush日志,将flush redo调整到了binlog flush阶段,以实现redolog的组提交

if (prepare_trx
	    || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {

		/* We were instructed to prepare the whole transaction, or
		this is an SQL statement end and autocommit is on */

		ut_ad(trx_is_registered_for_2pc(trx));

		dberr_t	err = trx_prepare_for_mysql(trx);

		ut_ad(err == DB_SUCCESS || err == DB_FORCED_ABORT);

		if (err == DB_FORCED_ABORT) {

			innobase_rollback(hton, thd, prepare_trx);

			return(convert_error_code_to_mysql(
				DB_FORCED_ABORT, 0, thd));
		}

	} else {
		/* We just mark the SQL statement ended and do not do a
		transaction prepare */

		/* If we had reserved the auto-inc lock for some
		table in this SQL statement we release it now */

		lock_unlock_table_autoinc(trx);

		/* Store the current undo_no of the transaction so that we
		know where to roll back if we have to roll back the next
		SQL statement */

		trx_mark_sql_stat_end(trx);
	}

[MySQL源码]:2PC下的事务提交概述

你可能感兴趣的:(MySQL)