全局的 LOCK 结构体里有一个 grantMask,它记录了“当前这张表被所有人加上了哪些锁”。
既然全局已经有了状态指示灯,为什么在 PROCLOCK(人与物的契约)结构体内部,还要单独设计一个 holdMask(持有掩码) 字段?
我们继续用**“假设没有它会发生什么灾难”**的底层逻辑推演法,分 4 步把它在 C 语言级别的绝对物理作用推导出来!
第一步绝境:单进程多重加锁(锁升级的物理现实)
【工业级场景】
在真实的复杂业务中,一个业务进程(PGPROC_A)在一个长事务里,对同一张表往往不止加一次锁。
例如:
- 进程 A 先执行了一句
SELECT * FROM orders。此时,它向orders表申请了 1 级锁(AccessShareLock)。 - 紧接着在同一个事务里,进程 A 又执行了一句
UPDATE orders SET ...。此时,它又向orders表申请了 3 级锁(RowExclusiveLock)。
【物理推演】
在内存中,内核绝对不会为进程 A 和 orders 表生成两个 PROCLOCK 契约!
为了节省极其宝贵的共享内存,无论进程 A 对这张表加多少种不同级别的锁,它们之间永远只能共享那唯一的一个 PROCLOCK_A 结构体。
第二步绝境:释放时的“物理失忆”(全局掩码的盲区)
【假设反推:如果没有 holdMask】
假设全局的 LOCK 结构体的 grantMask 现在的二进制位是 00000101(表示这张表目前同时存在 1 级锁和 3 级锁)。
现在,进程 A 的事务结束了,它调用 COMMIT 准备释放资源。
内核顺着指针找到了 PROCLOCK_A,准备去修改全局的 grantMask。
灾难发生了:
内核看着 PROCLOCK_A,脑子里一片空白。内核不知道:“进程 A 当初到底是只加了 1 级锁,还是只加了 3 级锁,还是两个都加了?”
如果不知道进程 A 到底持有什么锁,内核就绝对不敢去贸然扣减全局的 grantMask。如果扣错了,别的进程持有的锁状态就会被物理破坏,整个并发控制系统瞬间崩溃!
第三步破局:holdMask 的诞生(精准的私有账本)
为了解决这种“物理失忆”,架构师在 PROCLOCK 结构体内部,强制加入了一个极其轻量级的整数型字段:holdMask(当前进程对当前资源的私有持有掩码)。
它的物理运转逻辑(位运算)如下:
- 第一次加锁:进程 A 申请 1 级锁成功。
- CPU 动作:
PROCLOCK_A -> holdMask |= 00000001(第 1 位标为 1)。
- CPU 动作:
- 第二次加锁(锁升级):进程 A 申请 3 级锁成功。
- CPU 动作:
PROCLOCK_A -> holdMask |= 00000100(第 3 位也标为 1)。 - 此时
holdMask的物理状态:00000101。这本“私有账本”极其精准地记录了:进程 A 当前在这个契约上,同时挂着 1 级和 3 级两把锁。
- CPU 动作:
第四步终极推演:$O(1)$ 的安全释放与契约销毁
当事务 COMMIT,或者执行 ROLLBACK TO SAVEPOINT(回滚到某个保存点,需要释放部分锁)时,holdMask 展现出了它作为架构枢纽的绝对统治力。
- 精准扣减:内核读取
PROCLOCK_A -> holdMask,瞬间知道进程 A 手里攥着 1 级和 3 级锁。内核可以极其安全地去重新计算全局LOCK上的grantMask,绝不会误伤其他并发进程。 - 契约的物理生命周期判定:如果进程 A 只是释放了 3 级锁,但还要保留 1 级锁。
- CPU 动作:利用异或或按位与非运算,将
holdMask里的第 3 位抹零(变回00000001)。 - 内核决断:只要
holdMask的值不等于 0,说明进程 A 还有锁在这个表上,这个PROCLOCK结构体的内存就绝对不能free()掉! - 只有当
holdMask被彻底扣减为00000000时,内核才确认:双方彻底银货两讫。此时,内核才会安全地执行unlink,将PROCLOCK_A从双向链表中摘除,并物理销毁。
- CPU 动作:利用异或或按位与非运算,将
架构师闭环总结
在面试海量数据的内核级排障岗位时,你可以这样进行终极输出:
“在 PostgreSQL 的锁管理器中,全局
LOCK->grantMask是所有人的汇总状态,用来进行 $O(1)$ 的全局冲突判定;而
PROCLOCK->holdMask是单个进程的私有台账,它记录了当前进程对当前资源累积持有的所有锁级别。它的核心作用,是在事务执行‘锁升级’、‘部分释放(Savepoint)’以及‘最终提交’时,提供绝对精准的本地状态追溯,从而指导内核安全地重算全局掩码,并决定当前PROCLOCK结构体是否应该被物理销毁。”
这种从“变量丢失会导致什么内存灾难”反向推导出来的底层逻辑,不仅严密,而且充满了工程美感。
了解 www.876873.xyz 的更多信息
订阅后即可通过电子邮件收到最新文章。
逻辑推导出 holdMask 字段 的作用:等您坐沙发呢!