InnoDB---深入理解事务提交--02
来源:互联网 发布:长春干部网络学校 编辑:程序博客网 时间:2024/05/22 20:56
三 为什么说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()这个函数中执行如下重要代码,所幸的是,这段代码中有段很重要的注释,帮助我们回答了本标题提出的问题。
/*********************************************************************//**
Releasesa transaction's locks, and releases possible othertransactions 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 */
{...
/* Thefollowing assignment makes the transaction committed in memory //这段注释很重要,需要重点理解
and makesits changes to da
NOTE thatthere 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
logsegment has been flushed to the disk. If the database happens to
crashbefore the flush, the user has seen modifications from T which //在日志被刷出前,恰巧数据库引擎崩溃,而事务T被标识已经提交
willnever be a committed transaction. However, any transaction T2 //即使事务T2看到了事务T崩溃前且还没有刷出的数据,事务T2要想使
whichsees the modifications of the committing transaction T, and //自己的修改生效,T2需要获取一个比事务T的LSN更大的一个LSN
whichalso itself makes modifications to the database, will get an lsn //当系统恢复的时候,事务T因为没有预写日志而被回滚,而事务T2也只能回滚(暗含之意是LSN会被用于识别并发事务的提交顺序)
largerthan the committing transaction T. In the case where the log //刷出日志时需要使用LSN判断合法性
flushfails, 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 bedone. */
} else if(trx->flush_log_later) {
/* Do nothingyet */
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_on
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 ofthe ACID properties) in database systems.
In a system using WAL, all modificationsare written to a log beforethey are applied. Usually both redo and undo information is storedin the log.
上面第二句话是说,在被修改的数据被应用之前日志要刷出,被修改的数据被应用即是数据被其他事务可见(注意不应理解为被修改的数据被刷出到外存),可见对应的就是事务状态被设置为已经提交。所以我们才说InnoDB不符合预写日志机制。
[1] 源自:https://en.wikipedia.org/wiki/Write-ahead_logging
- InnoDB---深入理解事务提交--02
- InnoDB---深入理解事务提交--02
- InnoDB---深入理解事务提交--01
- InnoDB---深入理解事务提交--03
- InnoDB---深入理解事务提交--01
- InnoDB---深入理解事务提交--03
- InnoDB深入理解
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 深入理解分布式事务
- 长事务的管理
- InnoDB---事务和并发控制相关的文件
- InnoDB---UNDO日志与回滚
- fork实现
- InnoDB---深入理解事务提交--01
- InnoDB---深入理解事务提交--02
- Linux开发疑问apt-get upate 出现无法连接的问题
- java日期
- Integer和int的区别
- 数组那些不为菜鸟所知的秘密(零)
- InnoDB---深入理解事务提交--03
- 二分法二 F
- InnoDB定义的Mutex--01
- 多线程中的BlockingQueue(阻塞队列)