天天看點

漫談OceanBase的多版本并發控制

OceanBase的MemTable包含兩個部分:索引結構及行操作鍊。其中,索引結構存儲行頭資訊,采用記憶體B樹實作;行操作連結清單中存儲了不同版本的修改操作,進而支援多版本并發控制。

OceanBase支援多線程并發修改,寫操作拆分為兩個階段:

  • 預送出(多線程執行):事務執行線程首先鎖住待更新資料行,接着,将事務中針對資料行的操作追加到該行的未送出行操作連結清單中,最後,往送出任務隊列中加入一個送出任務。
  • 送出(單線程執行):送出線程不斷地掃描并取出送出任務隊列中的送出任務,将這些任務的記錄檔追加到日志緩沖區中。如果日志緩沖區到達一定大小,将日志緩沖區中的資料同步到備機,同時寫入主機的磁盤日志檔案。記錄檔寫成功後,将未送出行操作連結清單中的cell操作追加到已送出行操作連結清單的末尾,釋放鎖并回複用戶端寫操作成功。

如下圖所示,MemTable行操作連結清單包含兩個部分:已送出部分和未送出部分。另外,每個事務管理結構記錄了目前事務正在操作的資料行的行頭,每個資料行的行頭包含已送出和未送出行操作連結清單的頭部指針。在預送出階段,每個事務會将cell操作遞加到未送出行操作連結清單中,并在行頭儲存未送出行操作連結清單的頭部指針以及鎖資訊,同時,将行頭資訊記錄到事務管理結構中;在送出階段,根據事務管理結構中記錄的行頭資訊找到未送出行操作連結清單,連結到已送出行操作連結清單的末尾,并釋放行頭記錄的鎖。

class ObTransExecutor
{
public:
    //處理預送出任務
    void handle_trans(void* ptask, void* pdata);
    //處理送出任務
    void handle_commit(void* ptask, void* pdata);
};           
漫談OceanBase的多版本并發控制

obTransExecutor是UpdateServer讀寫事務處理的入口類,它主要包含兩個方法:handle_trans以及handle_commit。其中,handle_trans處理預送出任務,handle_commit處理送出任務。handle_trans首先将寫事務預送出到MemTable中,接着将寫事務加入送出任務隊列。送出線程不斷地從送出任務隊列中取出送出任務,并調用handle_commit進行處理。每個寫事務會根據送出時的系統時間生成一個事務版本,讀事務隻會讀取在它之前送出的寫事務的修改操作。

如下圖所示,對主鍵為1的商品有2個寫事務,事務T1(送出版本号為

2)将商品購買人數修改為100,事務T2(送出版本号為4)将商品購買人數修改為50。那麼,事務T2預送出時,T1已經送出,該商品的已送出行操作鍊包含一個cell:(update,購買人數,100),未送出操作鍊包含一個cell:(update,購買人數,50)。事務T2成功送出後,該商品的已送出行操作鍊将包含兩個cell:(update,購買人數,100)以及(update,購買人數,50),未送出行操作鍊為空。對于隻讀事務:

  • T3:事務版本号為1,T1和T2均未送出,該行資料為空。
  • T4:事務版本号為3,T1已送出,T2未送出,讀取到(update,購買人數,100)。盡管T2在T4執行過程中将購買人數修改為50,T4第二次讀取時會過濾掉T2的修改操作,因而兩次讀取将得到相同的結果。
  • T5:事務版本号為5,T1和T2均已送出,讀取到(update,購買人數,10)以及(update,購買人數,50),購買人數最終值為50。
漫談OceanBase的多版本并發控制