标签:
在存储系统中,redo日志可以应对那些已经执行成功的事务没有反映到磁盘时系统崩溃情形的数据恢复,但是,有时候会有另外一种情形,一个事务中,有多步操作,有部分操作已经成功,有部分操作失败,导致整个事务不能被完整执行,或者一个事务的执行过程中,人为的终止此事务的执行。不能被完整执行的事务,其中已经执行的步骤对于数据元素的修改已经反映到磁盘,或者反映到内存。根据事务的原子性原语,对于没有执行成功的事务,必须被当着像没有发生过一样。这种情形下,使用另外一种日志---undo日志,来保证事务的原子性,undo日志也具有三个原语
<BEGIN T>
<T, A, x> 此原组表示事务T中,数据元素A被修改前的旧值是x
<COMMIT T>
在更新一个数据元素过程中,系统遵循下面的规则,
修改任何一个数据元素前,向日志文件添加一个undo日志记录,以保存此数据元素被修改前的旧值
根据事务的隔离原则,在添加<COMMIT T>成功后,当前事务中对于数据元素的修改才能被反映到系统
我们仍然以从账户A转50元到账户B,在前一个涌道图中,增加undo日志,为了表示方便,这里假设同时写redo日志和undo日志
+----------------+-------+-------+----------------+----------------+ | OP | M-A | M-B | REDO LOG | UNDO LOG | +----------------+-------+-------+----------------+----------------+ | | | | <BEGIN T1> | <BEGIN T1> |(1) | READ(A, a) | 200 | | | |(2) | a = a - 50 | | | | |(3) | | | | <T1, A, 150> | <T1, A, 200> |(4) | OUTPUT(A, a) | 150 | | | |(5) | READ(B, b) | | 200 | | |(6) | b = b + 50 | | | | |(7) | | | | <T1, B, 250> | <T1, B, 200> |(8) | OUTPUT(B, b) | | 250 | | |(9) | | | | <COMMIT T1> | <COMMIT T1> |(10) +----------------+-------+-------+----------------+----------------+
在这个示意图中,如果崩溃点是发生在(10)之后,说明此事务已经被完整的执行,可以被重做redo日志,恢复数据;如果崩溃点发生在步骤(6),此时,A的新值150已经被反映到磁盘中,根据事务的原子性,我们需要撤销这个操作,幸运的是,undo日志记录中有数据元素A的旧值200,把这个旧值写回磁盘的操作叫undo操作或者叫撤销操作。在这个例子中,崩溃点发生在步骤(6) ~ (10)之间皆表示这个事务需要被撤销。
系统恢复后,从undo日志的尾部开始扫描undo日志记录,遵循下面的规则
如果一个事务具有<COMMIT T>记录,则忽略此事务,如果发现一个事务没有<COMMIT T>记录,或者具有<ABORT T>记录,则撤销此事务
如果事务Ti早于事务Tj发生,先撤销事务Tj,再撤销事务Ti
在一个被撤销的事务内,如果undo日志记录<T, A, x>早于<T, B, y>发生,则先执行<T, B, y>,再执行<T, A, x>
redo日志所使用的检查点技术也可以应用在undo日志。
还有一种应对故障的方式是讲redo日志和undo日志进行合并,称为redo/undo日志,使用一个四元组<T, A, x, y>表示事务使用新值x更新数据元素A,其旧值是y,系统在记录redo/undo日志时,只需要遵循一条规则
在更新数据元素前,把此数据元素的新值和旧值使用<T, A, x, y>的形式写入日志文件。
对于账户A转50元到账户B这个操作,带有redo/undo日志的涌道图,形式如下
+----------------+-------+-------+------------------+ | OP | M-A | M-B | REDO/UNDO LOG | +----------------+-------+-------+------------------+ | | | | <BEGIN T1> |(1) | READ(A, a) | 200 | | |(2) | a = a - 50 | | | |(3) | | | | <T1,A,150,200> |(4) | OUTPUT(A, a) | 150 | | |(5) | READ(B, b) | | 200 | |(6) | b = b + 50 | | | |(7) | | | | <T1,B,250,200> |(8) | OUTPUT(B, b) | | 250 | |(9) | | | | <COMMIT T1> |(10) +----------------+-------+-------+------------------+
使用redo/undo日志恢复数据时,首先从日志的头部开始扫描,对于所有已经commit的事务,组成redo列表,执行重做操作,再从日志的尾部扫描,组成undo列表,执行撤销操作。
redo日志的检查点也适用redo/undo日志。
原创日志,若有转载,请著名作者@仪山湖
标签:
原文地址:http://my.oschina.net/yishanhu/blog/465947