生產環境開啟 innodb_change_buffering=all 時,偶發 UNABLE TO PURGE A RECORD 錯誤。官方於 2015 年 2 月修復(Bug #73767)。
INSERT → IBUF_OP_INSERTDELETE → IBUF_OP_DELETE_MARK(打刪除標記)PURGE → IBUF_OP_DELETE(物理清理)UPDATE → IBUF_OP_DELETE_MARK + IBUF_OP_INSERTInnoDB MVCC 實現:刪除/更新僅打標記,後台 Purge 線程異步物理清理並回收 Undo Log 空間。
假設表 t(id PK, c1 KEY),頁不在 Buffer Pool。
1. DELETE FROM t WHERE id=1; → IBUF_OP_DELETE_MARK
2. INSERT INTO t VALUES(1,'a'); → IBUF_OP_INSERT(新紀錄無刪除標記)
3. Purge 線程執行 IBUF_OP_DELETE,發現待刪紀錄無刪除標記 → 拋錯。
若順序為 1→3→2 則不報錯。根因:Purge 與用戶更新操作無嚴格同步,導致 Purge 清理到未打標記的新紀錄。
row_purge_remove_sec_if_poss_leaf → row_search_index_entry → btr_pcur_open_func → btr_cur_search_to_nth_level → ibuf_should_try (判斷是否用 ibuf)
ibuf_insert 緩存 Purge 操作。ibuf_insert 時,先檢查 Watch 標記,若存在則放棄 ibuf,同步讀頁合併 Purge 操作,避免衝突。不走 ibuf 時,Purge 會調用 row_purge_poss_sec 確認聚簇索引記錄是否可 Purge(無刪除標記或 trx_id 較新則跳過),天然避開衝突。
在 Purge 使用 ibuf 前,先 buf_page_get_gen 設 Watch,再調用 row_purge_poss_sec 判斷可否 Purge。若用戶已 Re-insert,Purge 直接忽略;否則繼續 ibuf_insert。
同時修正用戶更新操作:真正使用 ibuf 前必須重新檢查 Watch 標記,確保無 Purge 併發使用 ibuf。
官方修復提交:ec369cb