PostgreSQL checkpoint 逻辑分析

源码版本:PostgreSQL 13.3

1. checkpoint 触发条件

  • 参数 checkpoint_timeout 控制,默认 5 分钟,范围 30s ~ 1 day
  • wal 日志间隔,当最新的 wal 日志与上次 checkpoint 时的 wal 日志的距离大于指定点时,触发。相关参数:checkpoint_complete_target
  • 手动触发,执行命令:checkpoint(超级用户)
  • 此外,数据库正常关闭,备份,崩溃恢复后,都会做 checkpoint

2. checkpoint 主要过程

PG 有专门负责做 checkpoint 的后台进程,其入口函数为 CheckpointerMain(),该函数会进入一个无限循环,在满足一定条件时,就会自动做 checkpoint 操作。

checkpoint 也可以手动执行,在 psql 终端输入 checkpoint 命令时,调用函数 RequestCheckpoint(),然后给 PG 的 checkpoint 进程发送 SIGINT 信号,请求该进程执行 checkpoint 操作。

checkpoint 的进程在收到 SIGINT 信号后,会在 for 循环中被唤醒,开始执行 checkpoint 操作,实际调用的函数为 CreateCheckPoint()。

3. CreateCheckPoint() 主要逻辑

  1. 获取 checkpoint 的 redo 点,即当前 wal 日志的最新写入点,在 checkpoint 完成后,如果发生崩溃,将从该位置点进行恢复
  2. 调用 CheckPointGuts() 函数刷新脏页
    1. 遍历 buffer,将 DIRTY 的块状态改为 CHECKPOINT_NEEDED,此步骤在内存中完成,并不涉及磁盘操作
    2. 刷物理文件,从缓存中将脏块 fsync 到磁盘,此步骤涉及磁盘,将标记为 CHECKPOINT_NEEDED 的 block 写出到磁盘
  3. checkpoint 本身作为一条 wal 记录被记录到 wal 中,该记录的内容为 checkpoint 结构体
  4. 更新控制文件 pg_control
  5. 删除或者重命名不再需要的的 wal 文件

4. 源码片断

DDL 语句 checkpoint,调用函数 RequestCheckpoint() 请求执行 checkpoint 操作。

# 源码路径:src/backend/tcop/utility.c case T_CheckPointStmt: if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to do CHECKPOINT"))); RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT | (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE)); break;