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);
}