MySQL在8.0.41中终于修复了DDL期间(频繁的Purge操作)可能导致数据丢失的BUG,详细介绍参考 [1][2]。遗憾的是,这个问题没有被完全修复。新版本在PCursor::move_to_next_block函数中引入了save_previous_user_record_as_last_processed和restore_to_first_unprocessed,用于保存和恢复游标。但当游标通过乐观方式恢复,且当前页面的右兄弟中的记录合并至当前页面,则合并期间迁移的记录将全部丢失。
问题概述
现象:在 MySQL 8.0.41 版本中,执行 ALTER TABLE ... ALGORITHM=INPLACE 时,若并发purge导致发生页面合并(SMO),PCursor::move_to_next_block 可能跳过合并后的记录,导致数据丢失。 核心错误:游标恢复时仍指向原页面的 supremum 伪记录,未感知合并到当前页面的新记录。
根本原因
游标恢复逻辑存在缺陷
- 游标发生保存时总是指向页面末尾的 supremum 伪记录,如果没有记录从当前页面中删除。游标将通过乐观的方式重新锁定当前页面。并依然指向supremum 伪记录。
- 如果并发的删除操作(purge)导致当前页面的右兄弟被回收。其记录将搬迁至当前页面,由于游标恢复后仍然指向supremum,搬迁的记录将被错误的忽略。
复现
规避手动
- 在发生页面向左合并后,通过buf_block_modify_clock_inc(merge_block);禁用引用当前页面的游标通过乐观方式恢复(veDB已包含该修复)。
- 通过gh-ost等工具执行DDL