日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:52000
  • 待審:37
  • 小程序:12
  • 文章:1037587
  • 會員:756

為了提升分配 undo 段的效率,事務提交過程中,InnoDB 會緩存一些 undo 段。只要同時滿足兩個條件,insert undo 段或 update undo 段就能被緩存。

1. 關于緩存 undo 段

為了提升分配 undo 段的效率,事務提交過程中,InnoDB 會緩存一些 undo 段。

只要同時滿足兩個條件,insert undo 段或 update undo 段就能被緩存。

條件 1:undo 段中只有一個 undo 頁。

條件 2:這個唯一的 undo 頁中,已經使用的的空間必須小于數據頁大小的四分之三。以默認大小 16K 的 undo 頁為例,undo 頁中已經使用的空間必須小于 12K。

如果 insert undo 段滿足緩存條件,它會加入回滾段的 insert_undo_cached 鏈表頭部。

如果 update undo 段滿足緩存條件,它會加入回滾段的 update_undo_cached 鏈表頭部。

2. InnoDB 提交事務

二階段提交過程中,commit 階段的 flush 子階段,把 prepare 階段及之前產生的 redo 日志都刷盤了,把事務執行過程中產生的 binlog 日志都寫入 binlog 日志文件了。

sync 子階段根據系統變量 sync_binlog 的值決定是否觸發操作系統把 binlog 日志刷盤。

前兩個子階段,都只處理了日志,不涉及 InnoDB 的事務。這兩個階段完成之后,InnoDB 的事務還沒有提交,事務還處于準備提交狀態(TRX_STATE_PREPARED)。

commit 子階段才會真正提交 InnoDB 的事務,這個階段完成之后,事務就提交完成了。

commit 子階段提交 InnoDB 的事務,要做的事情有這些:

  • 修改 insert undo 段的狀態。
  • 生成事務提交號,用于 purge 線程判斷是否能清理某些 update undo 日志組中的 undo 日志。
  • 修改 update undo 段的狀態。
  • 把 update undo 段中的 undo 日志組加入回滾段的 history list 鏈表。purge 線程會從這個鏈表中獲取需要清理的 update undo 日志組。
  • 把事務狀態修改為 TRX_STATE_COMMITTED_IN_MEMORY。
  • 釋放事務執行過程中 InnoDB 給表或記錄加的鎖。
  • 重新初始化事務對象,以備當前線程后續使用。

2.1 修改 insert undo 段狀態

如果事務插入記錄到用戶普通表,InnoDB 會為事務分配一個 insert undo 段。

如果事務插入記錄到用戶臨時表,InnoDB 會為事務分配另一個 insert undo 段。

InnoDB 可能會給事務分配 0 ~ 2 個 insert undo 段。commit 子階段會修分配給事務的所有 insert undo 段的狀態。

如果 insert undo 段滿足緩存條件,它的狀態會被修改為 TRX_UNDO_CACHED,否則,它的狀態會被修改為 TRX_UNDO_TO_FREE。

事務提交完成之后,InnoDB 會根據狀態緩存或者釋放 insert undo 段。

2.2 生成事務提交號

事務提交號是事務對象的 no 屬性,通常用 trx->no 表示。

代碼里,對事務提交號的注釋是 transaction serialization number,直譯成中文應該稱為事務序列號,或者事務串行號。

因為 trx->no 是在事務提交時生成的,我們還是把它稱為事務提交號更容易理解一些。

只有 update undo 段需要事務提交號。purge 線程清理 update undo 日志時,會根據 update undo 段的 undo 日志組中保存的事務提交號,決定是否能清理這個 undo 日志組中的 undo 日志。

修改 update undo 段的狀態之前,InnoDB 會生成事務提交號,保存到事務對象的 no 屬性中。

// storage/innobase/trx/trx0trx.cc
static inline bool trx_add_to_serialisation_list(trx_t *trx) {
  ...
  trx->no = trx_sys_allocate_trx_no();
  ...
}

trx_sys_allocate_trx_no() 調用 trx_sys_allocate_trx_id_or_no() 生成事務提交號。

// storage/innobase/include/trx0sys.ic
// 生成事務 ID
inline trx_id_t trx_sys_allocate_trx_id() {
  ut_ad(trx_sys_mutex_own());
  return trx_sys_allocate_trx_id_or_no();
}
// 生成事務提交號
inline trx_id_t trx_sys_allocate_trx_no() {
  ut_ad(trx_sys_serialisation_mutex_own());
  return trx_sys_allocate_trx_id_or_no();
}

從上面的代碼可以看到,生成事務 ID 和事務提交號調用的是同一個方法,trx_sys_allocate_trx_id_or_no() 的代碼如下:

// storage/innobase/include/trx0sys.ic
inline trx_id_t trx_sys_allocate_trx_id_or_no() {
  ...
  // trx_sys_allocate_trx_id_or_no() 每次被調用
  // trx_sys->next_trx_id_or_no 加 1
  // trx_id 保存的是加 1 之前的值
  trx_id_t trx_id = trx_sys->next_trx_id_or_no.fetch_add(1);
  ...
  return trx_id;
}

trx_sys->next_trx_id_or_no 保存的是下一個事務 ID 或事務提交號,具體是哪個,取決于是生成事務 ID 還是生成事務提交號先調用 trx_sys_allocate_trx_id_or_no()。

也就是說,事務 ID 和事務提交號是同一條流水線上生產出來的。我們以 trx 1 和 trx 2 兩個事務為例,來說明生成事務 ID 和事務提交號的流程。

假設此時 trx_sys->next_trx_id_or_no 的值為 100,trx 1、trx 2 啟動和提交的順序如下:

  • trx 1 啟動。
  • trx 2 啟動。
  • trx 1 提交。
  • trx 2 提交。

其于以上假設,生成事務 ID 和事務提交號的流程如下:

  • trx 1 生成事務 ID,得到 100。trx_sys->next_trx_id_or_no 加 1,結果為 101。
  • trx 2 生成事務 ID,得到 101。trx_sys->next_trx_id_or_no 加 1,結果為 102。
  • trx 1 生成事務提交號,得到 102。trx_sys->next_trx_id_or_no 加 1,結果為 103。
  • trx 2 生成事務提交號,得到 103。trx_sys->next_trx_id_or_no 加 1,結果為 104。

從以上流程可以看到,事務 ID 和事務提交號都來源于 trx_sys->next_trx_id_or_no,相互之間不會重復。

2.3 修改 update undo 段狀態

如果事務更新或刪除了用戶普通表的記錄,InnoDB 會為事務分配一個 update undo 段。

如果事務更新或刪除了用戶臨時表的記錄,InnoDB 會為事務分配另一個 update undo 段。

InnoDB 可能會給事務分配 0 ~ 2 個 update undo 段。commit 子階段會修改分配給事務的所有 update undo 段的狀態。

如果 update undo 段滿足緩存條件,它的狀態會被修改為 TRX_UNDO_CACHED,否則,它的狀態會被修改為 TRX_UNDO_TO_PURGE。

2.4 undo 日志組加入 history list

修改完 update undo 段的狀態,update undo 段的 undo 日志組會加入回滾段的 history list 鏈表。purge 線程會從這個鏈表中獲取要清理的 undo 日志組。

前面已經生成了事務提交號,這里會把事務提交號寫入 undo 日志組的頭信息中。

如果 update undo 段的狀態為 TRX_UNDO_CACHED,表示這個 undo 段需要緩存起來。它會加入回滾段的 update_undo_cached 鏈表頭部,以備后續其它事務需要 update undo 段時,能夠快速分配。

3. InnoDB 提交事務完成

前面的一系列操作完成之后,InnoDB 提交事務的操作就完成了。

現在,要把事務狀態修改為 TRX_STATE_COMMITTED_IN_MEMORY。

修改之后,新啟動的事務就能看到該事務插入或更新的記錄,看不到當前事務刪除的記錄。

接下來,InnoDB 會釋放事務執行過程中加的表鎖、記錄鎖。

釋放鎖之后,還要處理 insert undo 段。

如果 insert undo 段的狀態為 TRX_UNDO_CACHED,表示這個 undo 段需要緩存起來。它會加入回滾段的 insert_undo_cached 鏈表頭部,以備后續其它事物需要 insert undo 段時,能夠快速分配。

如果 insert undo 段的狀態為 TRX_UNDO_TO_FREE,它會被釋放,占用的 undo 頁會還給 undo 表空間。

二階段提交的 flush 子階段,已經把 prepare 階段及之前產生的 redo 日志都刷盤了。

commit 子階段,修改 insert undo 段和 update undo 段的狀態,還會產生 redo 日志。

InnoDB 不會主動觸發操作系統把這些 redo 日志刷盤,而是由操作系統決定什么時候把這些 redo 日志刷盤。

InnoDB 敢這么做,是因為這些 redo 日志對于確定事務狀態已經不重要了。即使這些 redo 日志刷盤之前,服務器突然異常關機,導致 undo 段的狀態丟失。MySQL 下次啟動時,也能正確的識別到事務已經提交完成了。

4. 重新初始化事務對象

到這里,InnoDB 提交事務該做的操作都已經做完了。提交事務完成之后,該做的事也都做了。

對于上一個事務,事務對象的使命已經結束。這里會把事務狀態修改為 TRX_STATE_NOT_STARTED。

事務對象也會被重新初始化,但是它不會被釋放。也就是說,事務對象不會回到事務池中,而是留給當前連接后續啟動新事務時復用。

5. 總結

InnoDB 提交事務,就像我們填完一個表格之后,最后蓋上的那個戳,總體上來說,要干 3 件事。

第 1 件,修改分配給事務的各 undo 段的狀態。

如果數據庫發生崩潰,重新啟動后,undo 段的狀態是影響事務提交還是回滾的因素之一。

第 2 件,修改事務對象的狀態。

如果數據據庫一直運行,不發生崩潰,就靠事務對象的狀態來標識事務是否已提交。

第 3 件,把各 undo 段中的 undo 日志組加入 history list 鏈表。

其它事務都不再需要使用這些 undo 日志時,后臺 purge 線程會清理這些 undo 日志組中的日志。

分享到:
標簽:MySQL
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 52000

    網站

  • 12

    小程序

  • 1037587

    文章

  • 756

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定