1. 假如一个数据页100行记录,是不是每对其中的任意一行记录做修改都要生成 WAL日志,wal日志生成后立刻把此刻的lsn 写入到 数据 页头部的pd_lsn里面,如果是这样,那修改100行记录,就要把数据页头部的 pd_lsn修改100次, 那最后这个脏页的 pd_lsn值究竟这么确定???
核心真相一:pd_lsn 的物理本质是“高水位线(High Water Mark)”
针对你的第一个问题:修改 100 行记录,是不是要生成 100 次 WAL?是不是要把 pd_lsn 修改 100 次?
架构师的绝对肯定:是的!在内存中,它就是被极其暴力地覆盖了 100 次!
【微秒级物理动作拆解】: 假设这 8KB 的数据页(假设是 10 号页)现在安安静静地躺在内存里。
- 第 1 次修改(改第 1 行):业务进程锁住 10 号页。生成一条 WAL 日志,拿到坐标
LSN = 1000。进程立刻把1000刻在 10 号页的pd_lsn上,然后释放锁。 - 第 2 次修改(改第 2 行):另一个业务进程锁住 10 号页。生成新的 WAL 日志,拿到坐标
LSN = 1050。进程极其冷酷地擦除掉刚才的 1000,把1050刻在pd_lsn上。 … - 第 100 次修改(改第 100 行):生成 WAL 日志,拿到坐标
LSN = 5000。进程把pd_lsn物理覆盖为5000。
【终极定性】: 在这 100 次修改期间,这个 8KB 页面一直都在内存里,绝对没有被刷入硬盘(它是一个极度肮脏的脏页)。 那么,这个脏页最终的 pd_lsn 是多少? 根本没有所谓的“最终值”,只有**“最新值”。在这个微秒,它的 pd_lsn 就是 5000。它永远只记录“导致该页面发生最后一次突变的那个最晚的 LSN 坐标”**。它就像一个高水位线,只记录洪水到达过的最高位置。
2. wal 日志的 lsn 和 脏页的pd_lsn做比较,来确定脏页的刷盘,在这种情况下如何比较??
针对 第二个问题:WAL 的 LSN 和脏页的 pd_lsn 到底怎么比较来决定能不能刷盘?
这就体现了内核架构师在 C 语言底层的极度聪明:利用 WAL 的绝对顺序性,实现“以一当百”的校验。
假设现在 bgwriter 或 checkpointer 进程游荡过来了,它选中了这个 10 号脏页,准备把它剁进物理硬盘。
【刷盘生死校验法则】: 刷盘进程看了一眼 10 号页的头部,读到:pd_lsn = 5000。 刷盘进程立刻转头去问底层日志系统:“喂!目前物理硬盘上,已经真正落盘(Flushed)的 WAL 日志,最高进度(Flushed_LSN)到哪了?”
此时,会出现两种物理时空状态:
- 状态 A(红灯拦截,绝对禁止下刀): 如果日志系统回答:“目前硬盘上的 WAL 只刷到了
Flushed_LSN = 3000。” 刷盘进程大脑瞬间报警:“脏页的pd_lsn (5000)>Flushed_LSN (3000)!” 物理逻辑: 这意味着,这个脏页里包含的第 100 次修改的记录(LSN 5000),目前还在 WAL Buffer(内存)里,没有落入硬盘!如果我现在把脏页刷进硬盘,万一立刻断电,硬盘上就会出现“数据改了,但日志没记”的极其恐怖的灵异事件! 动作: 刷盘进程立刻强制调用XLogFlush(5000),逼迫日志系统把 WAL 刷到 5000 以上,然后才敢把这 8KB 脏页写入数据文件。 - 状态 B(绿灯放行,安全落底): 如果日志系统回答:“刚才发生了组提交,WAL 已经一路狂刷到了
Flushed_LSN = 6000啦!” 刷盘进程检查:“脏页的pd_lsn (5000)<=Flushed_LSN (6000)!” 物理逻辑(解答你的核心疑惑): 刷盘进程根本不需要知道这个页面之前被改过 100 次,也不需要知道之前的 LSN 是 1000 还是 1050。 因为 WAL 日志是严格顺序追加的!既然连最晚产生的LSN 5000都已经安全躺在硬盘上了,那么从1000到4999的所有这 100 次修改的 WAL 记录,在物理学上必然已经全部安全落盘了! 动作: 畅通无阻,直接调用pwrite()把这 8KB 砸进数据文件!
了解 www.876873.xyz 的更多信息
订阅后即可通过电子邮件收到最新文章。
关于LSN的两个问题::等您坐沙发呢!