关系型数据库管理系统:事务处理Durability(持久性)的实现

来源:互联网 发布:妇幼保健网络信息系统 编辑:程序博客网 时间:2024/05/22 08:49

一、目的:Transaction commit后,结果持久有效,crash不消失。

二、想法一:在transaction commit时,把所有的修改都写回硬盘。只有当硬盘完成后,才commit。但是,这样会出现正确性问题;如果写多个page,中间掉电的话,Atomicity被破坏了!而且随机写硬盘、等待写完成也存在性能问题。

三、解决方案:WAL(Write Ahead Logging)

(1)Transaction Log事务日志

事务日志记录(Transactional Log Record):记录一个写操作的全部信息。LSN:log sequence number

对Transaction中每个写操作产生一个事务日志记录。Transaction commit会产生一个commit日志记录。Transaction abort会产生一个abort日志记录。

日志记录被追加到日志文件末尾。

(2)Write-Ahead Logging

Write-Ahead:Logging总是先于实际的操作。

Loggig相当于意向,先记录意向,然后再实际操作。写操作:先Logging,然后执行操作。Commit:先记录commit日志记录,然后commit。

(3)WAL如何保证Durablity

条件:日志是Durable的

当出现掉电时,可以根据日志发现所有写操作。

对于一个Transaction,寻找它的commit日志记录。如果可以找到commit记录,然后根据日志记录,确保所有的写操作都完成了。如果没有找到commit记录,对每个写操作检查和恢复原值。

(4)如何保证日志Durable

简单方法:写日志记录时保证日志记录Durable。

write+flush:必须执行一个写操作,然后用flush保证写操作确实写到硬盘上了,并且等待flush结束。缺点就是太慢了。

其他方法:在内存分配一个缓冲区(Log buffer)。Log为硬盘上的日志文件。



日志写在log buffer中。当commit时write+flush log buffer。但是,这样的话Dirty page可能会被写回硬盘!掉电时,硬盘上数据已经修改,但是log没有记录

解决方法:Page header记录本page最新写的LSN。Buffer pool在替代写回一个dirty page时,必须保证page LSN之前所有的日志已经flush过了。保证:日志记录一定是先于修改后的数据出现在硬盘上

(5)Cheakpoint(检查点)

目的:使崩溃恢复的时间可控。如果没有checkpoint,可能需要读整个日志,redo/undo很多工作。

定期执行checkpoint。checkpoint里面包括:当前活动的事务表,包括事务的最新日志的LSN。当前脏页表,每个页最早的尚未写回硬盘的LSN

(6)Crash Recovery

系统定期把当前活跃的Transaction信息(tID,earliest LSN)记录在log中


ARIES算法:

<1> 分析阶段:

找到最后一个检查点:检查点的位置记录在硬盘的一个特定文件中

找到日志的崩溃点。

确定崩溃时的活跃事务和脏页。

最后一个检查点的活跃事务表和脏页表。正向扫描日志,遇到commit,rollback,begin更新事务表;同时记录每个事务的最新LSN。遇到写更新脏页表,同时记录每个页的最早尚未写回硬盘的LSN。

<2> redo阶段:

目的:把系统恢复到奔溃前瞬间的状态。

步骤:找到所有脏页的最早的LSN。从这个LSN向日志尾正向读日志。redo每个日志的修改记录。对于一个日志,如果其涉及的页不在脏页表中,那么跳过;如果数据页的LS>=日志的LSN,那么跳过;其他情况,修改数据页。

<3> undo阶段:

目标:清除未提交的事务的修改。

步骤:对于所有在崩溃时活跃的事务,找到这个事务最新的LSN,通过反向链表,读这个事务的所有日志记录。undo所有未提交事务的修改:undo时,比较数据页的LSN和日志的LSN,如果数据LSN>=日志的LSN,才进行undo。

原创粉丝点击