万字长文解析最常见的数据库恢复算法: ARIES

news2024/9/20 14:59:05

#万字长文解析最常见的数据库恢复算法: ARIES

首发地址: https://mp.weixin.qq.com/s/Kc13g8OHK1h_f7eMlnl4Aw

Introduction

image

上图中为基于 WAL 的数据库的一种可能的架构情况。其中,In-Memory Data 为数据库数据在内存中的组织形式,可以是 B 树,也可以是 hash table 或者其他可能的数据结构。Non-Valatile Storage 中的 Database 为这些数据刷新(flush)到持久化存储之后的组织形式。

Buffer Manager

Buffer Manager(BM) 控制 In-Memory Data 及其持久化数据之间的读写逻辑。当用户访问的数据不在 In-Memory Data 中, BM 会去 Non-Valatile Storage 中读取磁盘中该数据对应的 Page,并将其交由 Buffer Pool 管理。如果 Memory 中的剩余空间不足以读取该 Page,BM 会根据指定的置换算法先将 Buffer Pool 中的部分 Page 逐出(evict)然后再读取。

当我们需要对某个 page 做操作时,需要先将这个 page fix 到 In-Memory Data 中。如果 page 不在内存中,fix 操作会将该 page 从磁盘中读取到内存。并且会让该 page 不会被置换算法逐出。当操作完成之后,对该 page 执行 unfix 操作,解除对该 page 的限制。

为了减少 I/O 对性能的影响,用户对 In-Memory Data 的变更,并不会立刻 flush 到 Non-Valatile Storage , 这会导致 它们中的数据可能会存在版本不一致的情况。BM 会 In-Memory Data 中比 Non-Valatile Storage 数据版本更新的数据由 Dirty Pages 统一维护起来,按照一定的规则统一 flush。(比如后台进程定期 flush;或是指定节点强制 flush)

对 Buffer Pool 的管理有两组策略来控制 flush 逻辑,第一组是 Steal/No-Steal :

  • STEAL: 变更中的 page 随时都可以被 flush 到持久化存储(即使变更事务还未结束)
  • NO-STEAL: 在涉及该 page 变更的事务结束(end of transaction, EOT)之前 ,不允许被 flush 到持久化存储。

另一组是 Force/No-Force:

  • FORCE: 在事务 commit 结束之前,需要确保事务所变更的 page 都已经 flush 到了持久化存储。
  • NO-FORCE: 在事务 commit 结束之前,不强制 flush。

一般来说 No-Force + Steal 因为不用强制刷屏,并且允许异步进程在任意时刻刷盘,所以性能最好。但是它的代价是需要同时维护 UNDO 和 REDO log 来保证数据的完整性和一致性。ARIES 就采用的是 No-Force + Steal 策略。

image

WAL(Write-Ahead Log) 日志

设想一下这个场景:某个请求对 In-Memory Data 的某个 Page X 做了变更。但在 Page X flush 进 Non-Valatile Storage 之前,整个系统因为某种原因重启了。此时,Page X 未 flush 的变更将会丢失。如果这部分变更之前已经 commit, 用户将会感知到数据丢失的发生。

为了解决上述问题, 我们需要使用 Write-Ahead Log(WAL),将 Dirty Pages 的变更提前写入 WAL 日志。这样在系统重启后,我们就可以通过 WAL 日志将 Dirty Pages 的变更恢复。 WAL 可以同步 flush,也可以较大频率的定期 flush。只有在某个事务 Txn 对应 WAL 日志已经全部 flush 成功的情况下,我们才认为事务 Txn commit 成功,可以向用户做出事务提交成功的响应。

一般来说 WAL log 有一下几类:

  • REDO LOG: 提供某个变更操作的重做信息。

  • UNDO LOG: 提供某个变更操作的回滚信息。

  • UNDO-REDO LOG: 既包含 REDO 信息又包含 UNDO 信息的日志。

  • Compensation Log Record(CLR): Undo 操作的 Redo Log。在 ARIES 中, 它是 Redo-only 日志。由于 UNDO 操作的信息在之前的被 Undo 的原操作操作对应的 WAL log 已经包含,因此,当我们在记录这条 UNDO 操作的 WAL log(redo-only) 时,仅需补偿指出它要 UNDO 的原操作的前一条操作,以便在 restart 过程中,快速定位到下一个待 UNDO 的原操作。

    在下图中,系统在 Recovery 过程中, 通过 CLR 日志 2’ 的信息发现当前应该对 1 进行回滚操作。因此,在 UNDO 阶段,对 1 进行回滚操作,并记录下它的 CLR 日志 1’。

    image

WAL 协议保证在某个 page 的变更 flush 到持久化存储之前,它所对应的 WAL 日志已经写入持久化存储。也就是说,至少保证某个变更的 UNDO log 已经 flush,才允许对应的变更 flush,只有这样,我们才能保证未完成的事务可以顺利的 UNDO。同时每个持久化的 page 携带有当前 page 上次刷盘对应的变更日志的 LSN,以便后续 recovery 操作时,定位该 page 的起始 redo log。

ARIES(Algorithms for Recovery and Isolation Exploiting Semantics) 是一种能够恢复系统状态并处理系统崩溃带来的问题的重要技术。该算法为处理数据库中的恢复、并发控制和事务管理问题等提供了全面的解决方案。它将上述的架构系统的整合在一起,提供一种通用化的处理思路。当前市面上绝大多数数据库的 Recovery 逻辑都是基于 ARIES 优化改造实现的。

本文将详细介绍 ARIES paper 的细节,完整展现数据库系统是如何实现 Recovery 的。

ARIES 概览

WAL 日志记录

ARIES 的 WAL 日志记录结构如下:

  • LSN: WAL 日志记录的第一个字节的地址,这是一个单调递增的值。
  • Type: 表示WAL日志记录的类型,可以是补偿日志(compensation) 也可以是更新日志(update)或是其他类型的日志。
  • TransID:如果 WAL 日志记录属于某个事务,则此字段记录该事务的 ID。否则,该字段为空。
  • PrevLSN: 记录同一个事务的前序 WAL 日志记录的 LSN。非事务相关或事务第一条日志记录的 PrevLSN 为 0(避免显式记录 BEGIN_TRANSACTION)。
  • PageID: 仅在 Type 为 update 和 compensation 的日志记录中出现。标记当前日志涉及到变更的 Page。
  • UndoNxtLSN: 仅在 Type 为 compensation 的日志记录(CLR)中出现。记录当前补偿日志对应的原日志的 PrevLSN,标记 UNDO 过程中的下一个待处理的日志记录的 LSN。如果该事务已经没有可 UNDO 的日志,则该字段为零。
  • Data:记录更新操作的 UNDO/REDO 信息。

在下图中,事务 tx1 在 LSN = 7 处回滚,开始执行回滚 LSN=3 的日志,并为其写下 LSN = 8 的 CLR log, 该日志指向下一个待 UNDO 的日志的 LSN, 即 LSN = 3 的日志对应的 PrevLSN(1)。

image

Page 结构

在数据库 Page 的元信息中,维护了一个 PageLSN 字段。该字段记录应用到该 Page 的最新的更新操作对应的 WAL 日志记录的 LSN。

如在下图中,下面的数轴表示 WAL 日志,数轴上面的数字表示 WAL 日志的 LSN。下面的 P1/P2 标记表示当前 WAL 日志涉及到变更的 Page。虚线箭头表示 Page flush 的 LSN。

在该图中, P1 flush 到了 PageLSN=2 处的日志,但其 buffer pool 中的数据已经变更到 PageLSN=5 处的日志(如果在当前状态下 crash,则 P1 需要从 pageLSN = 2 之后开始 recovery)。

image

活跃事务表(Active Transaction Table, ATT)

ATT 是负责追踪活跃事务的执行状态的状态表,包括以下字段:

  • TransID: 事务ID。
  • State: 事务状态。Prepared§ 或 Unprepared(U)。
  • LastLSN: 本事务已写的最新的 WAL 日志记录的 LSN。
  • UndoNxtLSN: Rollback 过程中待处理的下一条 WAL 日志记录的 LSN。如果当前事务的最新的 WAL 日志记录不为 CLR 的 Undo-able日志,则该字段设为 LastLSN。否则该字段设为该 CLR 日志的 UndoNxtLSN。

image

脏页表(Dirty Page Table, DPT)

DPT 用于记录数据库运行过程中 Buffer Pool 中已变更但还未来得及 flush 到持久化存储的 Page(即缓冲区中与持久化存储版本不一致的 Page)。包含以下字段:

  • PageID: Dirty Page 的 ID
  • RecLSN(Recovery LSN): 某个不在 Buffer Pool中的 Page,在准备变更前会将当前的 WAL 日志的下一条待写入日志的 LSN 记录为当前的 RecLSN。该 LSN 对应的日志将可能是该 Page 变更的第一条日志的写入点(因为可能有其他并发操作,因此该 Page 也可能是在此 LSN 之后写入),此时这些 Page 变更还未被 flush 到持久化存储。当某个 Dirty Page 被 flush 到持久化存储,该 Page 对应在 DPT 中的记录将会被删除。

在下图中,page L 和 Page M 持久化存储的数据版本早于内存中的数据版本,因此 Dirty Page 记录了它们对应的 RecLSN。page B 和 Page R flush 最新数据到持久化存储(内存数据和持久化存储数据版本一致),因此可以从 Dirty Page 中删除。
image

ARIES 的流程

  • 数据库正常运行状态下,后台任务定时刷新数据库运行状态 checkpoint 到 WAL 日志中,记录当前 DPT,ATT 的状态。同时在持久化存储的 Master Record 记录最新的 checkpoint 起始 LSN。

  • 事务的 Rollback :

    • 从事务的 UndoNxtLSN 开始执行 UNDO 操作, * 如果该日志为 Undo-able 日志,则先在 buffer 中的 Page 执行 Undo 操作,然后在 WAL 中写入补偿日志(原日志的 PrevLSN 为补偿日志的 UndoNxtLSN ),更新该事务的 LastLSN 为补偿日志的 LSN,UndoNxtLSN 为原日志的 PrevLSN 。
      • 如果该日志为补偿日志,则将 市纪委 UndoNxtLSN 设为该补偿日志的 UndoNxtLSN。
      • 否则, 将事务的 UndoNxtLSN 设为当前日志的 PrevLSN。
        *重复上述操作,知道 RollBack 完成。

image

  • Restart Recovery 的三个阶段
    • Analysis Pass: 先通过 Master Record 获取最新的 checkpoint,并通过 checkpoint 恢复 ATT 和 DPT。然后获取所有 Dirty Page 的最小 PageLSN 作为 REDO 的起点(RedoLSN)。同时梳理出正在 回滚的事务,在后续 Restart UNDO 阶段继续回滚。
    • Redo Pass: 从 Redo LSN 开始顺序执行 Redo log,直到 WAL 日志结尾(end of log)
    • Undo Pass: 逆序遍历处理 Rollback 事务,流程与正常的日志 Rollback 表现一致。

ARIES Normal Process

Update

ARIES Normal Process 流程如下图,当服务接收到业务数据更新请求,会现在 BufferPool 中更新对应的 Page,如果它不在 Dirty Page 中,则将它加入 Dirty Page。然后在内存中的 WAL 日志增加本次变更的内容,最后将 WAL flush 到磁盘。当 WAL flush 到磁盘后,该数据更新请求完成,返回业务请求成功。

同时,异步 flush 进程,定时将 Buffer Pool 中的 Page flush 到磁盘,并将其从 Dirty Page 中移除。
image

Rollback

为了支持部分回滚(partial rollback), 在事务执行过程中,会在特定时间节点建立 savepoint 记录当前事务最新写入的日志 LSN,记作 SaveLSN。如果当前事务还未写入日志,则 SaveLSN 设为 0。

同一个事务可以根据需要维护任意多个 savepoint。当事务需要回滚到某个 savepoint 时, 它会从最新的 WAL 日志开始执行 UNDO 操作,指定指定 savepoint 对应的 SaveLSN 为止。

事务回滚过程中, SaveLSN 之后申请的 lock 也会被释放(因为 ARIES 不会 UNDO CLR 日志, 因此在此场景下不再需要这些锁)。因此,当系统检测到出现死锁问题时,仅需要 partial rollback 到指定 savepoint 即可解决, 而不用 total rollback。

回滚过程中, 会从 ATT 中记录的 UndoNxtLSN 开始逆序 UNDO 所有可被 UNDO 的日志记录,并为其记录 REDO 日志(即 CLR 日志)。该 CLR 日志的 UndoNxtLSN 为原日志的 PrevLSN。因为 CLR 日志为 Redo-Only,因此,当 Rollback 过程中遇到 CLR 日志时,会直接跳过。

如果当前 UNDO 的原日志为非 CLR 日志,则下一个待 UNDO 的日志为当前原日志的 PrevLSN。 如果当前 UNDO 的原日志为 CLR 日志,则下一个待 UNDO 的日志为当前日志的 UndoNxtLSN(这将跳过已经被 UNDO 的日志)。

RollBack 伪代码如下:
image

下图展示了事务在回滚过程中的操作逻辑:

  1. 事务 T1 的 WAL log 2,3 已经完成 partial rollback,并产生 CLR 日志 3’和 2’。此时继续推进事务写入了 WAL 日志 4。此时 T1 因为某些原因需要完全 Rollback。
  2. 从 ATT 中读取 T1 的 UndoNxtLSN(4)。该日志为非 CLR 日志,因此在 Undo 日志 4 的同时,需要为它写入 CLR 4’, 4’ 的 UndoNxtLSN 指向事务 T1 中日志 4 的前驱日志 2’。同时更新 ATT 中 T1 的 LastLSN 为 4’, UndoNxtLSN 为 2’。
  3. 由于 2’ 为 CLR 日志,因此不需要对该日志做 Undo 操作。更新 ATT 中的 T1 的 UndoNxtLSN 为 2’的 UndoNxtLSN(1)。
  4. 日志 1 为非 CLR 日志,因此在 Undo 日志 1 的同时,需要为它写入 CLR 1’。由于事务 T1 中没有日志 1 的前驱日志,因此标记 CLR 1’ 的 UndoNxtLSN 为 0(标识已 Undo 完成)。同时更新 ATT 中 T1 的 LastLSN 为 1’, UndoNxtLSN 为 0。 此时事务 T1 Undo 完成,可以从 ATT 中删除该事务。
    image

Fuzzy Checkpoint

为了减少重启恢复过程中需要处理的 WAL 日志的数量,ARIES 定期在 WAL 日志中记录 Checkpoint 信息。

Checkpoint 日志以 begin_chkpt 为起点,以 end_chkpt 为结束,记录当前 ATT, DPT 的信息,以及当前正在使用的文件映射信息等。只有当 end_chkpt 完全写入的 Checkpoint 才是完整的,否则该 Checkpoint 信息将会被忽略。

Checkpoint 构建和写入过程中,并不阻塞其他的事务操作。比如下图中, Checkpoint 的 begin_chkpt 和 end_chkpt 之间还有其他事务的日志写入。既有 begin_chkpt 之前发起的事务 T1 的日志,也有 begin_chkpt 之后发起的事务 T2 的日志。它们既可以在 end_chkpt 之前结束(T2),也可以在 end_chkpt 之后结束(T1)。

image

ARIES 在构建 Checkpoint 过程中,并不需要强制 Dirty Page flush 到可持久化存储。因为 flush 操作由 Buffer Manager 按照其策略自动执行,而 Checkpoint 只负责将当前时间节点下的 flush 状态和其他必要信息记录下来,以便后续快速恢复。

ARIES Restart Processing

当系统重启,先从 MasterRecord 中读取到系统终止前最新的完整记录的 Checkpoint 的起始 LSN,然后依次执行重启 Analysis 和重启 Redo 并更新 DPT,接着执行重启 Undo,并为所有的 prepare 状态的事务重新获取 lock。最后记录新的 Checkpoint 记录重启流程的处理结果。伪代码如下图:

image

Analysis Pass

分析阶段会传入 MasterRecord 的 LSN,并返回恢复后的 DPT 和 ATT,以及 REDO 开始的位置 RedoLSN。

初始化阶段,通过 MasterRecord 的 LSN 读取到 MasterRecord,然后利用 MasterRecord 记录的最新 Checkpoint 的 begin_chkpt 的位置。然后,从 CheckPoint 的 begin_chkpt 开始分析 WAL 日志,直到 WAL 日志结束(end of log)。

在日志分析过程中,如果遇到 WAL 日志对应的事务不在 ATT 中,则将其加入 ATT。当分析的日志为 end_chkpt, 则通过 Checkpoint 日志记录的信息,恢复 ATT 和 DPT 的数据。如下图伪代码所示:

image

如 Normal Processing 所介绍那样, Checkpoint 日志写入期间,可能会并发存在其他并发写入事务的日志。因此,在恢复 DPT 时,如果发现某个 Dirty Page 已经写入被其他日志恢复到 DPT, 则只需要更新 DPT 中 该 Dirty Page 的 RecLSN 为 Checkpoint 记录的 Dirty Page 的 RecLSN。

当分析的日志为 Update 或 CLR 日志,则在 Restart Redo 阶段需要对它进行 REDO。因此在 DPT 中,如果不存在该日志对应的 Page,则需要将该日志对应的 Page 插入 DPT 中(该 Page 将在 Redo 阶段变更)。

同时,在 ATT 中更新当前日志对应事务的 LastLSN 为当前日志的 LSN(事务最新日志的 LSN)。如果当前日志为 Update 且是可 Undo 的,则记录将 ATT中该事务的 UndoNxtLSN 更新为当前日志的 LSN。如果当前日志为 CLR 日志,则该事务的 UndoNxtLSN 为当前日志的 UndoNxtLSN。

image

当分析到事务的 Prepare/Rollback 操作日志时,会将 ATT 表中当前日志对应事务的 LastLSN 设为当前日志的 LSN。同时,如果当前日志为 Prepare,将 ATT 中对应的 State 设为 “P(Prepared)”。 如果当前日志为 Rollback,则将 ATT 中对应 State 设为 “U(Unprepared)”。在 Undo 阶段, 所有处于 “U” 状态的事务,都将被回滚。

事务的 end 日志,表示事务已经成功的提交,因此不需要再 ATT 中维护这个事务。因此当分析到 end 日志时,直接在 ATT 中删除对应事务。

image

在分析阶段的最后,将 Redo 日志的起始位置 RedoLSN 设为 DPT 中所有 Dirty Page 的 RecLSN 的最小值。(如果 DPT 为空,则表示没有需要 Redo 的日志,可以跳过 Redo 阶段)。

完整伪代码如下:

image

Redo Pass

Redo 阶段以分析阶段生成的 RedoLSN 和 DPT 为输入,从 RedoLSN 开始扫描处理日志,直到最后一条日志。

当遇到Redo 的日志记录时,会检查对应的 Page 是否在 DPT 中存在。如果存在,并且当前日志的 LSN 大于或等于表中该页的 RecLSN,那么该日志可能需要被 Redo。继续读取该页的 PageLSN, 如果 PageLSN 小于当前日志的 LSN,则该日志需要重做。否则忽略该日志,

为什么某个 Page 的 PageLSN 可能会不小于它在 DPT 的 RecLSN ?

因为 PageLSN 记录的事实际 flush 到 Page 的 LSN, 而 RecLSN 记录的是 Checkpoint 恢复的 Dirty Page 信息。由于 Page Flush 和 Checkpoint 的 Flush 完全并行,互不影响, 因此可能存在 Checkpoint Flush 之后,再次执行了 Page Flush ,导致恢复的 Checkpoint Dirty Page 信息延迟与实际 Page Flush 的信息。因此 DPT 的 RecLSN 小于实际的 PageLSN。

image

如上图,空心点表示事务 T1 的 WAL 日志, 实心点表示 T2 的日志。虚线箭头表示持久化存储中的 P1, P2 当前 flush 的数据对应的最新的 LSN(即,PageLSN)。 可以看到在系统 Failure 时, 持久化存储中的 P1 的 PageLSN 为 2, P2 的 PageLSN 为 7。

根据分析阶段的结果, 在 Redo 时,会从 DPT 中最小的 RecLSN 作为 Redo 操作的起始日志 RedoLSN。在本例中 RedoLSN=3。

Redo 阶段,从 Failure 前最新的 Checkpoint 记录恢复的 DPT 中,P2 的 RecLSN 为 4(这个 Checkpoint 不知道在 LSN=7 处的日志已经 flush)。而P2 对应的 PageLSN 实际上为 7。此时的 P2 的 RecLSN <= PageLSN,因此 LSN 为 4 的操作已经被 flush 到持久化存储,不需要 Redo。同理,也不需要 Redo LSN=7 的日志。

而 Checkpoint 记录的 P1 的 RecLSN=3,大于 P1 flush 到 Page 的 LSN(PageLSN = 2)。因此,LSN 为 3, 5 的 WAL 日志对 P1 的变更还未被 flush 到持久化存储,需要被 Redo。

在 Redo 阶段执行的操作都不会记录在 WAL log 中,因为它本身就是在 Redo 之前的 Redo Log(即执行的操作已经记录)。

Redo 的完整伪代码如下:

image

Undo Pass

Undo 阶段,以 ATT 作为参数,每次从 ATT 中读取失败事务(待回滚)最大的 UndoNxtLSN 处理,直到所有的回滚事务已经处理完成。伪代码如下:

image

Undo 阶段对待回滚事务的处理和 Normal Processing 的回滚操作一样。如果当前 UNDO 的原日志为非 CLR 日志,则下一个待 UNDO 的日志为当前原日志的 PrevLSN。如果当前日志为可 Undo 日志,则为其执行 Undo 操作,并记录该操作的 CLR 日志。 如果当前 UNDO 的原日志为 CLR 日志,则下一个待 UNDO 的日志为当前日志的 UndoNxtLSN(这将跳过已经被 UNDO 的日志)。

下图 demo 中,描述了 ARIES 重启恢复中的单个事务的回滚流程。

image

在正常运行状态下, 事务 partial rollback 对 WAL 日志 3, 4 执行了 UNDO 操作,产生了 CLR 日志 4’ 3’。接着继续推进事务写入 WAL 日志 5,6。在 6 写入持久化存储之后,系统由于某些原因导致了重启。此时, 最新记录的 Checkpoint 的 DPT 中最小 RecLSN 为 2。

ARIES 在 Restart Recovery 时, 会从 3 开始 REDO, 直到日志的结尾。即,3,4,4’, 3’,5,6。

然后再 Undo 阶段, 从 6 开始 undo,产生 CLR 6’。然后是对 5 undo 产生 CLR 5’。 接着在处理 3’ 时,发现它为 CLR 日志,因此直接跳转到它的 UndoNxtLSN(2) 继续处理。依次对 2,1 undo 并产生 CLR 日志 2’,1’ ,完成 Recovery Restart 流程。

image

上图所示,

  1. 在 restart recovery 的前两个阶段,恢复的 WAL log 和 ATT 的内容如图所示。
  2. 读取到当前 ATT 表中处于 ‘U’状态事务的 UndoNxtLSN 最大值为 5(T2)。该日志为非 CLR 日志,因此可以在 Undo 该日志之后,为该日志写入 CLR 日志 5’,该 CLR 日志的 UndoNxtLSN 指向事务 T2 下一个待 Undo 的日志 2。同时更新 ATT 表中 T2 的 LastLSN 为 5’, UndoNxtLSN 为 2。
  3. 读取到当前 ATT 表中处于 ‘U’状态事务的 UndoNxtLSN 最大值为 3’(T1)。该日志为 CLR 日志,因此不需要对该日志做 Undo 操作。直接将 ATT 表中 T1 的 UndoNxtLSN 设为 3’ 的 UndoNxtLSN(1)。
  4. 读取到当前 ATT 表中处于 ‘U’状态事务的 UndoNxtLSN 最大值为 2(T2)。该日志为非 CLR 日志,因此可以在 Undo 该日志之后,为该日志写入 CLR 日志 2’。由于原日志 2 没有当前事务的前序日志。因此将该 CLR 日志的 UndoNxtLSN 设为 0(表示事务 T2 回滚完成)。同时更新 ATT 表中 T2 的 LastLSN 为 2’, UndoNxtLSN 为 0。(ATT 表中的这一项可以被移除)
  5. 读取到当前 ATT 表中处于 ‘U’状态事务的 UndoNxtLSN 最大值为 1(T1)。该日志为非 CLR 日志,因此可以在 Undo 该日志之后,为该日志写入 CLR 日志 1’。由于原日志 1 没有当前事务的前序日志。因此将该 CLR 日志的 UndoNxtLSN 设为 0(表示事务 T2 回滚完成)。同时更新 ATT 表中 T2 的 LastLSN 为 1’, UndoNxtLSN 为 0(ATT 表中的这一项可以被移除)。至此,recovery restart 的 Undo 流程执行完成。

参考文献

  • Principles of Transaction-Oriented Database Recovery
  • Compensation Log Records (CLR) in UNDO-Phase of Database Recovery
  • ARIES: A Transaction Recovery Method Supporting Fine-Granularity Locking and Partial Rollbacks Using Write-Ahead Logging

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705051.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Element-ui 实现多个日期时间发范围查询

1、前端 <el-form-item label"生产时间"> <el-date-picker v-model"dateProduct" style"width: 240px" value-format"yyyy-MM-dd" type"daterange" range-separator"-" start-placeholder"生产开始…

(三)解析函数及其性质

本文主要内容如下&#xff1a; 1. 复变函数的导数与微分1.1. 复变函数可导、可微、解析与奇点的定义1.2. 复变函数可微的充要条件1.3. 关于复变函数可微性判定的其它形式1.4. 相关结论1.5. 解析函数的构造 2. 解析函数与调和函数2.1. 调和函数与共轭调和函数2.2. 解析函数与调和…

cglib bean复制报错:module java.base does not “opens java.lang“ to unnamed module

在使用cglib bean复制功能时&#xff0c;报下面的错误 Caused by: net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,b…

牛客社区项目续

统一日志记录 我们的这个项目在很多地方都需要记录日志&#xff0c;比如帖子模块、评论模块、消息模块等&#xff0c;而以前我们记录日志都是在某一个功能点中使用日志工厂&#xff0c;像下面这样&#xff1a; 项目中很多地方都需要记录日志&#xff0c;像这样一个地方一个地方…

sumo的几种安装方法

sumo的几种安装方法 sumo有很多中安装方法&#xff0c;根据你需要的任务来自己选择&#xff1a; 采用官网的latest version来进行安装 sudo add-apt-repository ppa:sumo/stable sudo apt-get update sudo apt-get install sumo sumo-tools sumo-doc想要安装源码来进行自己b…

【Java可执行命令】(六)调试工具 jdb:深入解析应用程序调试工具jdb ~

Java可执行命令详解之jdb 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法格式3.1.1 参数&#xff1a;-sourcepath < path>3.1.2 指令&#xff1a;run [class [args]]3.1.3 指令&#xff1a;print < expr>3.1.4 指令&#xff1a;stop at< class>:< line>…

如何利用Idea回滚代码以及Cherry-Pick部分代码

引言 大家在版本迭代过程中&#xff0c;是否遇到过开发好的需求&#xff0c;都已经合并到Master分支等待发布后&#xff0c;临时通知不需要上线了的情况。这个时候一般会要求只上一部分紧急功能或者别的新功能&#xff0c;那么这个时候就需要用到Git的Reset以及Cherry-Pick功能…

钉钉机器人用bitmap实现签到记录

现在是周五晚上&#xff0c;下面是一个二进制数字&#xff0c;其中&#xff0c;有16位&#xff0c;最后一位下标是15&#xff0c;今天晚上是14&#xff0c;我签到成功了

一定要收藏的30套可视化大屏制作模板!升职加薪不再是梦想!

前几天和朋友吃饭聊天&#xff0c;他吐槽说老板让他做可视化大屏&#xff0c;但他不会敲代码根本做不出来&#xff0c;老板动动嘴巴子根本不考虑技术难度只想看到成果&#xff0c;他焦虑得都睡不着觉。我给他分享了一套可视化大屏模板&#xff0c;10分钟就制作完成了老板要求的…

了解浏览器缓存

什么是HTTP缓存&#xff0c;如何工作的&#xff1f; 当我们打开一个页面时&#xff0c;会向服务端发起很多次请求&#xff0c;如下图打开百毒首页&#xff0c;发起了HTML、各种图片、JS、CSS等资源共101次请求。这里面很多资源并不会频繁变化&#xff0c;每次打开页面都重新请…

利用Python构建宁德时代、比亚迪、隆基绿能股票时间序列预测模型

存货 import tushare as ts # 导包 import numpy as np import matplotlib.pyplot as plt from scipy.signal import find_peaks from scipy.stats import norm import datetime import pandas as pd import seaborn as sns # pip install seaborn import matplotlib.patches …

Oracle报错:“Error in invoking target ‘agent nmhs’ of makefile...”

前言&#xff1a;Oracle在安装过程中的报错一定要重视&#xff0c;这决定你后续是否能完成安装以及是否能使用。我这边会陆续汇总一些报错现象以及解决方案共享。 ##Install Product 86%报错信息 &#xff1a;“Error in invoking target agent nmhs of makefile...”解决方案…

意大利语翻译哪个公司比较专业?

据了解&#xff0c;意大利语除了通行于意大利之外&#xff0c;还通行于美国、加拿大、阿根廷和巴西等29个国家的&#xff0c;其应用极为广泛。随着意大利语翻译需求量的日益增加&#xff0c;也促进了意大利语与其它语言间的交流、转化和发展。那么&#xff0c;意大利语翻译难吗…

抖音短视频矩阵号系统开源部署搭建分享(二)

开发背景&#xff1a;抖音seo源码&#xff0c;抖音矩阵系统源码。抖音获客系统源码&#xff0c;短视频矩阵系统源码开源搭建&#xff08;MySQL数据库&#xff0c;NGINX&#xff0c;PHP7.4&#xff0c;MySQL5.7&#xff0c;redis&#xff09; 技术要点&#xff1a; 服务器配置服…

vue-router.esm.js:2248 Error: Cannot find module ‘@/views/dylife/ 报错解决

具体是展示 一直加载 控制台报找不到模块 webpack版本问题&#xff0c;webpack4 不支持变量方式的动态 import &#xff0c;新版本需要使用 require() 来解决此问题。 return () > import(/views/${view}) 改写成 return (resolve) > require([/views/${view}], reso…

python接口自动化(四)--接口测试工具介绍(详解)

简介 “工欲善其事必先利其器”&#xff0c;通过前边几篇文章的介绍&#xff0c;大家大致对接口有了进一步的认识。那么接下来让我们看看接口测试的工具有哪些。 目前&#xff0c;市场上有很多支持接口测试的工具。利用工具进行接口测试&#xff0c;能够提供测试效率。例如&…

【C++】浅析C++中的虚函数

关于虚函数 Q1&#xff1a;观察一个类引入虚函数后&#xff0c;类会发生什么变化&#xff1f; 首先&#xff0c;创建一个空类A&#xff0c;并实例化出A的一个对象a&#xff0c;计算一下这个对象占用多少字节&#xff1a; #include<iostream> using namespace std;clas…

02-阴影

使用阴影 1.给立方体添加castShadow&#xff0c;让立方体产生阴影 cube.castShadow true;2.创建一个地面用于接收阴影 const planeGemetry new THREE.PlaneGeometry(20, 30)const planeMaterial new THREE.MeshPhongMaterial({ color: 0xffffff })const plane new THREE.…

LeetCode 2. 两数相加

文章目录 1. 题目描述2. 解题代码 1. 题目描述 链接&#xff1a;https://leetcode.cn/problems/add-two-numbers/ 2. 解题代码 public ListNode AddTwoNumber(ListNode l1, ListNode l2) {ListNode head new ListNode();ListNode cur head;int carry 0;while (l1 ! null…

CIO 访谈|财达证券 IT 基础架构云化转型思考与实践

作为河北省证券行业的主力军&#xff0c;财达证券始终坚持用科技赋能业务&#xff0c;全方位推动信息化和数字化建设。在本期视频中&#xff0c;我们请到了财达证券首席信息官谢井民&#xff0c;分享如何基于 SmartX 超融合逐步实现 IT 基础架构云化转型&#xff0c;满足公司“…