在通用日志文件系统(CLFS)中,给定流中的每个日志记录都由日志序列号(LSN)唯一标识。 将记录写入流时,可以返回一个 LSN,用于标识该记录以供将来引用。
为特定流创建的 LSN 构成了严格增加的序列。 也就是说,分配给给定流中的日志记录的 LSN 始终大于以前写入到该流中的日志记录的 LSN。 以下函数可用于比较给定流中日志记录的 LSN。
CLFS_LSN_NULL和CLFS_LSN_INVALID常量是所有有效 LSN 的下限和上限。 任何有效的 LSN 都大于或等于CLFS_LSN_NULL。 此外,任何有效的 LSN 严格小于CLFS_LSN_INVALID。 CLFS_LSN_NULL是有效的 LSN,而CLFS_LSN_INVALID不是有效的 LSN。 即便如此,也可以使用上一列表中的函数将CLFS_LSN_INVALID与其他 LSN 进行比较。
对于每个流,CLFS 将跟踪两个特殊的 LSN:基本 LSN 和最后一个 LSN。 此外,每个单独的日志记录都有两个特殊的 LSN(前一个 LSN 和撤消下一 LSN),可用于创建相关日志记录链。 以下部分详细介绍了这些特殊的 LSN。
基本 LSN
当客户端在流中写入第一条记录时,CLFS 会将基本 LSN 设置为该第一条记录的 LSN。 在客户端更改基础 LSN 之前,基本 LSN 保持不变。 当流客户端不再需要流中某个点之前的记录时,可以通过调用 ClfsAdvanceLogBase 或 ClfsWriteRestartArea 来更新基本 LSN。 例如,如果客户端不再需要前五条日志记录,则可以将基本 LSN 设置为第六条记录的 LSN。
最后一个 LSN
当客户端将记录写入流时,CLFS 会调整最后一个 LSN,以便始终是写入的最后一条记录的 LSN。 如果客户端不再需要流中某个点之后的记录,则可以通过调用 ClfsSetEndOfLog 更新最后一个 LSN。 例如,如果客户端不再需要在第十条记录之后写入的任何记录,则可以通过将最后一个 LSN 设置为第十条记录的 LSN 来截断流。
流的活动部分
流的 激活部分 是指从基准 LSN 所指向的记录开始,到最后一个 LSN 所指向的记录结束的那部分流。 下图说明了基本 LSN 和最后一个 LSN 如何描述流的活动部分。
如果流具有存档尾部,则流的活动部分从基 LSN 或存档尾部指向的记录开始,以较小者为准。 有关存档的详细信息,请参阅 CLFS 对存档的支持。
上一个 LSN
假设两个活动数据库事务(事务 A 和事务 B)正在同时将记录写入同一流。 每次事务 A 写入记录时,它将记录的上一个 LSN 设置为事务 A 写入的上一日志记录的 LSN。这构成了属于事务 A 的日志记录链,可以按相反顺序遍历。 该链以事务 A 写入的第一条日志记录结束,该记录的上一个 LSN 设置为CLFS_LSN_INVALID。 同样,事务 B 通过设置它写入的每个日志记录的上一个 LSN 来创建自己的日志记录链。
下图中的箭头说明了日志记录的上一个 LSN 如何指向属于特定事务的链中的上一条记录。
撤消下一个 LSN
假设事务对易失性内存中的数据对象进行五次更新,回滚第四次和第五次更新,然后进行第六次更新。 当事务进行更新时,它会写入日志记录 1、2、3、4、5、5'、4'和 6。 日志记录 1 到 5 描述了更新 1 到 5 所做的更改。 记录 5' 描述了在更新 5 回滚期间所做的更改,记录 4' 描述了更新 4 回滚期间所做的更改。 最后,记录 6 描述了 update 6 所做的更改。 数字 1、2、3、4、5、5'、4'和 6 不是日志记录的 LSN;它们只是用于命名此讨论的日志记录的数字。
描述回滚的日志记录 5' 和 4'称为补偿日志记录 (CLR)。 该事务将每个 CLR 的撤消下一个 LSN 设置为其更新回滚(撤消)的日志记录的前一代(事务写入的记录)。 在此示例中,记录 5' 的后撤 LSN 是记录 4 的 LSN,记录 4' 的后撤 LSN 是记录 3 的 LSN。
普通日志记录(不是 CLR)将其撤消的下一个 LSN 设置为事务写入的以前的日志记录。 也就是说,对于普通记录,撤消下一个 LSN 和以前的 LSN 是相同的。
现在假设系统出现故障,在重启恢复期间,必须回滚整个事务。 恢复代码读取日志记录 6。 记录 6 中的数据指示记录 6 是普通记录(而不是 CLR),因此恢复代码回滚更新 6。 然后,恢复代码检查记录 6 的撤消下一个 LSN,并发现它指向记录 4'。 记录 4’中的数据表明它是 CLR,因此恢复代码不会回滚更新 4’。 相反,它会检查记录 4' 的撤消下一个 LSN,并发现它指向记录 3。 记录 3 不是 CLR,因此恢复代码回滚更新 3。 更新 5 和 4 不会在恢复期间回滚,因为它们已在常规正向处理期间回滚。 最后,恢复代码回滚更新 2 和 1。
下图说明了 "undo-next LSN" 如何为恢复代码提供一种机制,使其可以跳过已回滚更新的记录。