这一节将会讨论ARIES所使用到的主要数据结构。
接下来,我们将要说明不同日志记录里的比较重要的字段:
LSN:在日益增长的日志地址空间中记录的第一个字节。它是一个单向增长的值。这里把它作为一个字段只是为了更好的描述ARIES。LSN实际上并不需要存储在记录中。
Type:标识这条记录的类型:补偿记录('compensation'),常规更新记录('update'),提交协议相关的记录(比如'prepare'),或者非事务型记录(比如'OSfile_return').
TransID:事务的标识,如果有的话,写到日志记录中。
PreLSN:同一事务之前写的一条日志记录的LSN,在非事务日志和事务的首条记录中该字段为0,从而省去了要显示定义一条事务开始日志。
PageID:只有在“补偿”和“更新”记录类型中才有该字段。标明了待更新的记录在哪一页上。PageID通常包含两个部分:一个objectID(比如:tablespaceID),一个该对象内的页号。ARIES可以处理一条对于多页更新的日志记录。为了讨论方便,我们假设每条日志记录只会影响一个页。
UndoNxtLSN:只有在CLR中才包含此字段。表示的是某事物进行回滚时,下一条日志记录的LSN。也就是说,UndoNxtLSN是当前日志记录对这条记录的PrevLSN的补偿值。如果没有记录需要回滚,该字段值就是0.
Data:这个是redo和(或者)undo数据,用来描述了此次更新如何执行。由于CLRs从不undone,所以它只包含redo信息。更新可以以逻辑方式记录。页的某些字段的变更(比如:空闲空间的统计)并不需要记录下来,因为它们可以很容易的推导出来。对于整个对象的undo和redo信息都不需要记录。将这些变更字段单独记录就足够用了。对于自增,自减操作,该字段的前后镜像也不需要。操作类型和增减量就足够了。这里的信息也会用来决定使用合适的操作例程来执行这条记录的redo和(或者)undo。
数据库的每一页都会包含page_LSN字段。它包含了对该页的最后一次更新的日志记录的LSN。这条记录可能是一条常规更新记录或者一个CLR。ARIES强制“缓存管理”执行WAL协议。除此之外,ARIES对缓存页替换策略没有其他限制。可能会使用steal缓存管理策略。原地更新发生在非持久化存储上。更新通常直接或间接的作用于包含该对象的缓存版本。也就是说,不会有延期更新,比如INGRES[86]。如果可以的话,可以支持延迟更新,继而延迟记录日志。ARIES是非常灵活的,并不排除可以应用这些策略。
在重启恢复是,一个被称为事务表的表用来跟踪该事务的活动状态。通过分析最近的一次checkpoint记录和在其后的日志记录来初始化该表。在undo的时候,该表也会发生变更。如果在重启恢复的时候进行checkpoint,那么该表的内容会包含在改checkpoint的记录中。事务管理模块同样使用相同的表来处理正常流程。下面描述了事务表中的一些重要的字段:
TransID:事务ID
State:该事务的提交状态:prepared('P'-也叫做in-doubt)或者unprepared('U')
LastLSN:事务写的最后一条日志记录的LSN
UndoNxtLSN:在回滚时,下一条待处理记录的LSN。如果该事务写的最近一条日志记录是回退型的non-CLR,那么该字段值应该设置为LastLSN.若最近一条日志记录是CLR,那么该字段值应该根据CLR来设置该值。
在正常处理时,使用脏页表来描述脏缓存页的信息。在重启恢复时也会使用到该表。对于该表的具体实现可以使用hash或者通过[96]的延迟写队列技术。该表中的每个实例包含两个部分:PageID和RecLSN(恢复LSN)。在正常处理时,当某个非脏页在缓存中被钉住准备修改,缓存管理模块就会在缓存池(BP)脏页表中记录RecLSN(当前尾记录的LSN,下一条将要写的日志记录的LSN)。RecLSN的值表示从日志的什么时候开始,更新还没有到页的持久化版本中。当页被写回到非易失存储中,BP脏页表中相应的实例就会被移除。在正常处理时,该表的内容会写入到checkpoint记录中。重启时是从最近一次checkpoint记录来初始化脏页表,并在分析其他记录时修改该表。由表中最小的RecLSN可以知道在重启恢复时,redo的起始点。