8.MEDIA RECOVERY介质恢复
我们假定介质恢复是在文件层面或者类似的层面(比如DB空间,表空间等等)。使用模糊镜像备份(页称之为模糊文件归档)来生成该实例,与此同时其他事务也可以操作该实例。由于这个是一个高并发镜像备份方法,该镜像备份中可能包含一些未提交的更新,与【52】中的方法恰恰相反。当然,如果需要的话,可以很容易的生成一个没有未提交变更的镜像备份。在此,我们假设该镜像备份是直接取自于非易事存储的某个版本。这就意味着某些备份页的最新版本还在事务系统的缓存中。在进行这样的备份操作时,由于可以使用设备的特性并节省了缓存管理的消耗,所以从非易失存储中备份将会十分高效。由于事务系统不需要直接处理备份,所以这比从其缓存中备份要容易的多。如果确实需要后者(比如,【13】中描述的支持增量镜像备份),页很容易修改现有的方法来支持它。当然,如果这样的话,将会需要一些少量的同步操作。比如,在页层面加闩,不需要加锁。
在模糊镜像备份开始时,将会记录最近一次完成检测点的begin_chkpt的位置,并且与镜像备份数据记录在一起。我们称其为镜像备份checkpoint。基于此checkpoint信息可以得知:那些LSN比min(min(该checkpoint的脏页中的RecLSN),LSN(该checkpoint的bigen_chkpt))的日志记录,在开始镜像备份操作时已经刷出到非易失存储上了。这样,该实例的镜像版本至少与此是日志中最新的。我们成此刻为media recovery redo point(介质恢复重做点)。在介质重做点中计算beign_chkpt中LSN的原因和5.4节中讨论计算restart redo point的所给的原因一样。
若要开始介质恢复了,就会装载其镜像备份版本,并且从介质恢复重做点开始redo遍历。在redo遍历时,所有涉及到正在恢复实例的日志记录都会被处理,并执行相应的更新操作,除非在checkpoint的脏页列表的信心或页上的LSN使其不需要这么做。和重启redo不同的是,如果一条日志的页不在脏页列表中,并且该日志的LSN比镜像备份checkpoint的begin_chkpt的LSN还大的话,那么就要访问该页,并比它的LSN和日志的LSN来检测这条更新操作是否需要redo。如果日志遍历结束,如果仍然有正在运行的事务,这些事务可以变成Undo的,正如重启恢复中的undo遍历。关于这些用来区分事务的标识(比如一种类似DB2的DBA表的异常表--参见6.4节),或者会从最后一次完整checkpoint到日志结束的分析遍历中获取到。
面向页的日志记录提供了对象恢复的独立性。由于在ARIES中,没有个数据页的更新都是分开记录日志的。所以,如果在非易失存储中某个页损坏了,若该页需要恢复,可以很容易的从镜像备份中获取该页的之前的一个版本,并且按照之前所说的方法,回滚到该页的这个版本。这和有些系统不同,比如System R,由于该系统中有些页更新(比如索引和表空间的页)并没有记录日志,对于这些页的恢复需要对完整对象的重新构建(比如,如果索引的某个页损坏了,就得重建整个索引),操作成本很高。同样对于一些显式记录的页(比如System R中的的数据页),如果执行Undo的时候没有记录CLR,那么如果从镜像备份状态将一个页更新到最新,就需要关注该日志记录所对于的事务状态(提交,部分或全部回滚),来决定要执行什么样的动作,是不是需要undo。如果某个事务已经部分或全部回滚,那么需要对该事务向后扫描来看看他们是否对那些已经恢复的页做了变更。这种向后扫描可能是做了无用功,因为一些回滚的事务并没有对已经恢复的页有任何影响。一种替代方案是:重处理那些日志,并且插入前置指针来跳过回滚的记录,System R在重启的分析遍历中就是这么做的(参见10.2节和图18)。
数据的单独页的损坏可能是因为介质问题,也有可能是因为该进程正在对缓存池中的页修改,并在进程将这些变更写到日志中之前,进程异常终止了。如果数据库代码是由业务进程调用执行的,比如一些关注性能的系统--DB2,这些异常终止可能是因为用户中断的(比如碰到一些特殊值)或者是操作系统的行为,比如该进程已经超出了CPU的时间限制。如果在每个页更新之前将该进程变为不可中断,将非常耗时。假定以下一些情况:一个高效的方法来将损坏的页恢复到正常版本,并使用与该页相关的所有日志记录将页更新到最新。对于日志的roll-forward redo 扫描是从记录在缓存中的RecLSN开始。DB2自动执行这种内部恢复操作。判断该页是否损坏是通过页头中的1个bit位来判断。如果该页被订住了并x-lathed。一旦更新操作完成(比如,页更新,日志更新,页的LSN修改),该bit位会置为0。通过这个,当将一个页闩住来读或写,首先检查该bit位是否为1,如果是1就会自动执行页恢复。从可用行的角度来看,因为一个页的损坏而进行重启恢复,redo对该页的所有日志更新,继而停止整个事务系统是不可接受的。一个相关的问题是要确保,当停止进程时,这些页是仍然处于fixed态的,事务系统需要发起unfix调用。通过对一些操作留下足够足迹,比如:fix,unfix,latch,用户进程可以帮助系统进程来处理一些必要的清理工作。
对于本节中提到多种原因,使用CLR是一种很好的思路,即使有些系统只支持页锁。这和no-CLR方案不同,【52】中提到的,它只支持页锁。