首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

InnoDB Purge 線程 Bug 復現與修復:DEBUG_SYNC 與 DBUG_EXECUTE_IF 並發同步技術深度解析

     編輯:MySQL 綜合教學

InnoDB Purge Bug 穩定復現技術:DEBUG_SYNC 與 DBUG_EXECUTE_IF 並發控制深度解析

MySQL InnoDB 核心模組中,Purge 線程、IO 線程、用戶工作線程並發操作 Insert Buffer (IBUF) 時,特定執行序列會觸發 UNABLE TO PURGE A RECORD 錯誤。因涉及多線程競態,隨機難以復現。本文詳述如何使用 MySQL 內建除錯機制 DEBUG_SYNC 與 DBUG_EXECUTE_IF 實現穩定復現,為修復提供可驗證基準。

問題背景與觸發條件

  • IBUF 操作類型:IBUF_OP_INSERT (插入)、IBUF_OP_DELETE_MARK (刪除標記)、IBUF_OP_DELETE (Purge 實際刪除)
  • Bug 觸發序列:DELETE_MARK → INSERT → DELETE 特定交錯順序
  • 涉及線程:用戶線程 (DML)、Purge 線程、IO 線程 (Merge)
  • 頁面不在 Buffer Pool 中 (需從磁碟讀取)

技術一:DEBUG_SYNC - 精確訊號同步

MySQL 原始碼巨集,透過訊號機制實現線程間精確同步。

1. 原始碼植入同步點

// 用戶線程執行 INSERT (產生 IBUF_OP_INSERT)
row_ins_step() {
    // ... 程式碼 A ...
    DEBUG_SYNC("after_user_insert_ibuf");
    // ... 程式碼 B ...
}

// Purge 線程執行 DELETE (產生 IBUF_OP_DELETE)
purge_step() {
    // ... 程式碼 a ...
    DEBUG_SYNC("after_purge_delete_ibuf");
    // ... 程式碼 b ...
}

2. Session 設定同步規則

-- Session 1 (用戶線程)
SET DEBUG_SYNC = 'after_user_insert_ibuf SIGNAL user_insert_done WAIT_FOR purge_delete_done';

-- Session 2 (Purge 線程,需透過 debug 介面或注入)
SET DEBUG_SYNC = 'after_purge_delete_ibuf SIGNAL purge_delete_done WAIT_FOR user_insert_done';
優點:精確控制執行順序;缺點:需修改原始碼重編譯、難以控制後台線程 (Purge/IO) 的 Session 設定。

技術二:DBUG_EXECUTE_IF - 睡眠延遲同步 (較實用)

在關鍵路徑植入條件式睡眠,透過全域 debug 變數啟用。

1. 原始碼植入睡眠點

// storage/innobase/ibuf/ibuf0ibuf.cc - ibuf_insert()
ibuf_insert(..., ibuf_op_t op, ...) {
    // 強制 Purge 的 DELETE 操作等待 3 秒
    DBUG_EXECUTE_IF("sleep_ibuf_insert_delete", {
        if (op == IBUF_OP_DELETE) my_sleep(3000000); // 微秒
    });
    ibuf_insert_low(...);
}

// storage/innobase/ibuf/ibuf0ibuf.cc - ibuf_merge_pages()
ibuf_merge_pages(...) {
    // 強制 Merge 操作等待 5 秒 (比 Purge 更久)
    DBUG_EXECUTE_IF("sleep_ibuf_merge", {
        my_sleep(5000000);
    });
    buf_read_ibuf_merge_pages(...);
}

2. 全域啟用除錯點

SET GLOBAL debug = '+d,sleep_ibuf_insert_delete,sleep_ibuf_merge';

3. 配合測試腳本觸發序列

-- 1. 設定小 Buffer Pool,掃描大表驅逐目標頁
SET GLOBAL innodb_buffer_pool_size = 16M;
SELECT * FROM large_table; -- 驅逐目標頁

-- 2. Session 1: 執行 DELETE (產生 DELETE_MARK)
DELETE FROM target_table WHERE id = 1;

-- 3. Session 2: 稍後執行 INSERT 同頁 (產生 INSERT)
INSERT INTO target_table (id, ...) VALUES (1, ...);

-- 4. 等待 Purge 線程自然運行 (產生 DELETE)
-- 因 sleep_ibuf_insert_delete 延遲 Purge 的 DELETE
-- 因 sleep_ibuf_merge 延遲 Merge
-- 即可穩定獲得 DELETE_MARK → INSERT → DELETE 序列

實戰關鍵細節

  1. 頁面不在 Buffer Pool:設極小 innodb_buffer_pool_size + 全表掃描驅逐
  2. 操作順序控制:DELETE 先於 INSERT 提交,確保 DELETE_MARK 先寫入 IBUF
  3. 睡眠時間調整:需反覆嘗試,確保 Purge 執行 DELETE 時 INSERT 已在 IBUF 中
  4. 日誌與除錯器:開啟 innodb_print_ddl_logs、GDB 斷點觀察關鍵變數

總結與啟示

  • DEBUG_SYNC:精確但侵入性強、需重編譯、適合單元測試框架
  • DBUG_EXECUTE_IF + sleep:輕量、可動態啟用、適合核心開發者快速復現並發 Bug
  • 並發 Bug 復現核心:**識別關鍵路徑 → 植入同步點 → 控制執行序列 → 驗證穩定復現**
  • 修復驗證同樣需穩定復現環境,確保補丁有效
參考資源: MySQL 官方除錯文件、何登成 MySQL 內核分析、GPFeng 博客。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved