快乐学习
前程无忧、中华英才非你莫属!

InnoDB—深入理解事务提交–02

来源:http://zblog.163.com/li_hx/blog/static/1839914132016112991511518/    作者:那海蓝蓝
 
三 为什么说InnoDB不符合WAL预写日志机制?

在标题二中我们提出这样的一个调用栈:

innobase_commit_low(trx)

-> trx_commit_for_mysql()

-> trx_commit(trx)

-> trx_commit_low()

-> trx_commit_in_memory()

-> lock_trx_release_locks()

lock_trx_release_locks()这个函数中执行如下重要代码,所幸的是,这段代码中有段很重要的注释,帮助我们回答了本标题提出的问题。

/*********************************************************************//**

Releases a transaction’s locks, and releases possible other transactions waiting because of these locks. Change the state of the transaction to TRX_STATE_COMMITTED_IN_MEMORY. */ //这段注释表明了lock_trx_release_locks()函数的功能

void

lock_trx_release_locks(

/*===================*/

trx_t* trx) /*!< in/out: transaction */

{…

/* The following assignment makes the transaction committed in memory //这段注释很重要,需要重点理解

and makes its changes to data visible to other transactions. //在内存里提交后,本事务的数据即对其他事务可见

NOTE that there is a small discrepancy from the strict formal //存在的一个问题:违反了WAL预写日志的机制

visibility rules here: a human user of the database can see //注释在说:即使违反了WAL预写日志的机制InnoDB也能保证正确性

modifications made by another transaction T even before the necessary

log segment has been flushed to the disk. If the database happens to

crash before the flush, the user has seen modifications from T which //在日志被刷出前,恰巧数据库引擎崩溃,而事务T被标识已经提交

will never be a committed transaction. However, any transaction T2 //即使事务T2看到了事务T崩溃前且还没有刷出的数据,事务T2要想使

which sees the modifications of the committing transaction T, and //自己的修改生效,T2需要获取一个比事务TLSN更大的一个LSN

which also itself makes modifications to the database, will get an lsn //当系统恢复的时候,事务T因为没有预写日志而被回滚,而事务T2也只能回滚(暗含之意是LSN会被用于识别并发事务的提交顺序)

larger than the committing transaction T. In the case where the log //刷出日志时需要使用LSN判断合法性

flush fails, and T never gets committed, also T2 will never get

committed. */

/*————————————–*/

trx->state = TRX_STATE_COMMITTED_IN_MEMORY; //此状态一旦设置,则本事务修改的数据则可以被其他事务所见(此时日志还没有被刷出到外存)

lock_release(trx); //释放事务锁(事务状态已经被设置,表明提交已经完成,本事务的数据可以被其他事务所见到,所以可以释放锁,这就是SS2PL中提交点应该在何时设置的技术本质)

}

这段代码的注释表明,InnoDB知道自己事务提交的规则“可能”不符合预写日志的规则也知道这样做带来的问题(可反复阅读上面的注释和解读),所以也提供了相应的解决问题的方式。解决方式如下面的代码调用栈:

innobase_commit()

{

innobase_commit_low(trx)

{

-> trx_commit_for_mysql()

-> trx_commit(trx)

-> trx_commit_low()

-> trx_commit_in_memory()

{

-> lock_trx_release_locks()

{

trx->state = TRX_STATE_COMMITTED_IN_MEMORY; //内存中设置事务提交的标志,本事务的数据即刻被其他事务可见

… //省略一些代码

lock_release(trx); //在设置事务提交已经完成的标志后才释放锁。锁在设置提交标志后才释放,符合SS2PL协议

}

lsn_t lsn = mtr->commit_lsn();//获得最新的LSN

if (lsn == 0) {

/* Nothing to be done. */

} else if (trx->flush_log_later) {

/* Do nothing yet */

trx->must_flush_log_later = true;

} else if (srv_flush_log_at_trx_commit == 0 //innodb_flush_log_at_trx_commit参数值为0,则不进行“预写日志”

|| thd_requested_durability(trx->mysql_thd)

== HA_IGNORE_DURABILITY) {

/* Do nothing */

} else { //否则,innodb_flush_log_at_trx_commit参数值为1,一定进行“预写日志”

trx_flush_log_if_needed(lsn, trx); //第一次写日志的机会,此时写日志,则符合预写日志机制

}

trx->commit_lsn = lsn; //LSN赋值到事务结构体,待下面执行trx_commit_complete_for_mysql(trx)时再刷出日志

}

}

if (!read_only) {

trx_commit_complete_for_mysql(trx); //重要的步骤:刷出日志(刷出日志的过程可参见下一节日志落盘中的标题二)

{ //第二次写日志的机会,此时写日志,则不符合预写日志机制

trx_flush_log_if_needed(lsn, trx) -> trx_flush_log_if_needed_low() -> log_write_up_to(lsn, flush);

}

}

}

从前面的分析可以看出,InnoDB是先设置了事务完成的状态,然后才刷出日志(第一次和第二次刷出日志的机会均在设置事务完成的状态之后),所以我们说InnoDB不符合预写日志机制。

下面请看预写日志(WAL)的定义[1]

In computer science, write-ahead logging (WAL) is a family of techniques for providing atomicity and durability (two of the ACID properties) in database systems.

In a system using WAL, all modifications are written to a log before they are applied. Usually both redo and undo information is stored in the log.

上面第二句话是说,在被修改的数据被应用之前日志要刷出,被修改的数据被应用即是数据被其他事务可见(注意不应理解为被修改的数据被刷出到外存),可见对应的就是事务状态被设置为已经提交。所以我们才说InnoDB不符合预写日志机制。


[1] 源自:https://en.wikipedia.org/wiki/Write-ahead_logging
打赏

未经允许不得转载:同乐学堂 » InnoDB—深入理解事务提交–02

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

特别的技术,给特别的你!

联系QQ:1071235258QQ群:226134712
error: Sorry,暂时内容不可复制!