交付一份快照验证与拒绝证书
快照读取与提交验证路线的终点是一份可以重新执行的事务记录。它不能只有最终键值:相同最终值可能掩盖不同读来源,提交失败也可能来自写写冲突、旧读失效或保守危险结构。报告须把这些决定分开。
下载标准库核验器。普通运行与 python -O 都使用显式条件检查,任何错误抛出异常;程序不连接数据库、不请求网络、不在后台发送请求,也不把有限输入通过当成真实数据库认证。
一、冻结对象与观察
使用固定键域0..15;键0表示x,键1表示y,值 None 表示不存在。初始版本的创建者为专用初始标识,提交序号为0。每次开始与提交尝试取得唯一递增边界序号;普通读、私有写可以夹在这些边界之间。
每笔事务记录开始序号、外部读的键/来源创建者/版本序号/数值、私有最终写,以及提交或中止结果。读取自己已经写过的值来自私有层;如果先前曾外部读过这个键,那份外部依据不能因后来写入而被删掉。
事务执行假设输入已经冻结、计算只影响私有状态。提交前不得把查询结果作为不可撤销响应,也不得发送外部业务副作用。附件展示并发控制,不负责网络调用幂等、掉电恢复或日志持久化。
二、同一份写偏差输入交给三种入口
初始x=y=1。A在边界1开始,读到两个初始版本,准备x=0;B在边界2开始,读到同一快照,准备y=0。两个业务程序都以“另一个值仍为1”为允许关闭自身的前提。让A在边界3先提交,再让B在边界4尝试。
- SI:两写集互斥,A、B都提交,最终x=y=0。图有A→rw(y) B及B→rw(x) A,找不到串行见证
- OCC:A验证通过;B在键x发现当前版本由A在3发布,晚于B的开始2,提交被拒绝。证书须列旧来源0和新来源A,不能只写“版本不同”
- SSI:B候选加入后,取I=A、pivot=B、O=A。两条并发rw边形成危险结构,O与I允许是同一事务;A先于B提交,过滤条件保留这份证书,所以B被拒绝
在两个拒绝分支,令B以新身份重新开始。它的新快照读到x=0,于是不再写y=0,成功完成后最终x=0、y=1。若仍重发旧W,就没有重跑条件判断,不能算安全重试。
报告应列“两个事务都成功”“一笔中止后重试”等真实结局,不把SI分支违反业务约束的预期结果删掉或改成通过同一安全断言。
三、把只读事务放进三环
换成初态x=y=0,按下表执行:
| 边界 | 操作 |
|---|---|
| 1 | P开始并读y的初始版本 |
| 2 | Q开始,私有写y=1 |
| 3 | Q提交 |
| 4 | R开始,读x=0以及Q的y=1 |
| 5 | 只读R提交 |
| 6 | P尝试发布x=1 |
在SI下三者都提交。交付版本链x₀→xP、y₀→yQ,随后按多版本依赖图逐条还原:
- P读y₀,Q发布后续版本,给P→rw(y) Q
- R读x₀,P发布后续版本,给R→rw(x) P
- R读到Q版本,给Q→wr(y) R
串行要求是Q在R前、R在P前、P在Q前。实际提交顺序Q、R、P不能替代这份依赖推理;P的x私有副本也从未成为R的来源。
SSI在边界6重建完整历史,取得I=R、pivot=P、O=Q。两端并发条件分别为R/P、P/Q,Q的提交3早于R快照4,也早于R和P的提交5、6。因此当前P可以中止,已经提交的Q、R保持原决定。
刻意把R的记录在边界5丢弃,再进行同一次验证:R→P这条边会消失。这说明读者提交后其证据仍可能被并发写者需要,不应沿用普通共享锁“提交就释放”的清理直觉。
四、让结构仍在,却没有环
只改一个动作:R不再读取y。开始、提交和其余读写全部不变。图中Q→R消失,剩下R→P→Q,其拓扑序R、P、Q保持所有读来源和版本次序。
SSI参考器仍会在P提交时找到同一双边链,提交次序和只读过滤也都通过,所以仍可能拒绝。它保护安全,却不是“恰好所有不可串行历史才中止”的判定器。需要交出这个合法串行顺序,作为误拒绝的证据,不能把没有查到返回路径写成已有环。
进一步迁移:去掉R,只运行P和Q。剩下一条P→rw Q,没有危险结构;SSI可接受两者并按P、Q解释。本页OCC却要求提交顺序Q、P,P的旧读y失效,所以会中止。两协议允许的并发历史不同,并非其中一方一定少做了检查。
五、三份接口反例
验证与发布之间不能留空窗
让A、B都在任何发布前检查完各自读集。两次检查都返回真,再分别发布x=0、y=0,最终约束失败。附件明确构造这一错误分支;正确入口应将检查与全部发布绑定成一个原子事件,或者另外加入有证明的并行验证机制。
盲写和读后更新不同
C、D并发开始,都不读x,分别盲写7和9。OCC读集为空,可按C、D提交顺序都接受,最终x=9;SI及本SSI入口按first-committer-wins只接受C,最终x=7。若把C、D改成读x后加一,就必须增加外部读集合,不能继续按盲写分支接受。
空查询不能省成空读集
在只有键8和15存在的场景中,考虑[10,13)为空后分别插11、12。扫描必须读取10、11、12的缺失版本,之后并发插入才能触发OCC旧读证书或SSI反依赖。
附件直接取全空数据库运行这个区间反例:两者读到空,SI双提交,而OCC/SSI拒绝后一个。读集应打印为三个键;若错误地只收集返回行,它会为空,两种后加检查便都失去所需输入。
六、安全只读快照的时序迁移
先开始一个明确只读的R,且当时没有活跃更新者。R读旧x;随后才开始P、Q,让P读旧y、Q发布y,再让P发布x,最后R提交。图可能有R→rw P→rw Q,但Q在R快照之后才提交,不满足只读危险结构的必要时序,因此这一链不能让参考器拒绝R。
与第三节对照,那里P在R开始之前已经活跃,并且有指向R快照之前Q的反依赖,不能提前宣称R安全。是否安全看的是完整的并发者与提交时点,不是R有没有执行UPDATE。
若要在开始时免除跟踪,只读承诺必须由接口强制执行;普通事务“当前还没写”不能借此豁免后再写。附件保守地始终记录读集,在提交时才利用已知W为空的事实过滤,不实现提前免跟踪的生产优化。
七、交付清单与复算方法
运行输出保留主轨迹、拒绝证书、重试与最终值。自查还应完成:
- 在三事务、两键的有限读写集合和边界次序中,独立枚举串行顺序,以读取来源与每键写者顺序直接核图的无环判据
- 对每份被SI接受的有环历史,找到满足并发、最早提交和只读过滤的危险结构;同时保留无环但仍有结构的实例计数
- 对SSI每一个接受前缀核无环和无合格危险结构,不能只检查最终数据库
- 对OCC的交错读写、盲写、删除及重试,按成功提交次序重新核所有外部读来源
- 保留普通和优化模式的实际结果;源码使用显式检查,二者必须字节一致
这些有限核验补充三个一般证明:版本图与固定版本序串行见证的等价、OCC的提交序归纳、SI环的相邻并发rw结构。它们没有覆盖任意SQL谓词、真实多核原子发布、有限内存回收或故障恢复,报告中应把这些尚未实现的接口留在边界之内。