自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL 核心模塊揭秘,你看明白了嗎?

數(shù)據(jù)庫 MySQL
為了提升分配 undo 段的效率,事務(wù)提交過程中,InnoDB 會(huì)緩存一些 undo 段。只要同時(shí)滿足兩個(gè)條件,insert undo 段或 update undo 段就能被緩存。

1. 關(guān)于緩存 undo 段

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

只要同時(shí)滿足兩個(gè)條件,insert undo 段或 update undo 段就能被緩存。

條件 1:undo 段中只有一個(gè) undo 頁。

條件 2:這個(gè)唯一的 undo 頁中,已經(jīng)使用的的空間必須小于數(shù)據(jù)頁大小的四分之三。以默認(rèn)大小 16K 的 undo 頁為例,undo 頁中已經(jīng)使用的空間必須小于 12K。

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

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

2. InnoDB 提交事務(wù)

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

sync 子階段根據(jù)系統(tǒng)變量 sync_binlog 的值決定是否觸發(fā)操作系統(tǒng)把 binlog 日志刷盤。

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

commit 子階段才會(huì)真正提交 InnoDB 的事務(wù),這個(gè)階段完成之后,事務(wù)就提交完成了。

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

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

2.1 修改 insert undo 段狀態(tài)

如果事務(wù)插入記錄到用戶普通表,InnoDB 會(huì)為事務(wù)分配一個(gè) insert undo 段。

如果事務(wù)插入記錄到用戶臨時(shí)表,InnoDB 會(huì)為事務(wù)分配另一個(gè) insert undo 段。

InnoDB 可能會(huì)給事務(wù)分配 0 ~ 2 個(gè) insert undo 段。commit 子階段會(huì)修分配給事務(wù)的所有 insert undo 段的狀態(tài)。

如果 insert undo 段滿足緩存條件,它的狀態(tài)會(huì)被修改為 TRX_UNDO_CACHED,否則,它的狀態(tài)會(huì)被修改為 TRX_UNDO_TO_FREE。

事務(wù)提交完成之后,InnoDB 會(huì)根據(jù)狀態(tài)緩存或者釋放 insert undo 段。

2.2 生成事務(wù)提交號(hào)

事務(wù)提交號(hào)是事務(wù)對(duì)象的 no 屬性,通常用 trx->no 表示。

代碼里,對(duì)事務(wù)提交號(hào)的注釋是 transaction serialization number,直譯成中文應(yīng)該稱為事務(wù)序列號(hào),或者事務(wù)串行號(hào)。

因?yàn)?trx->no 是在事務(wù)提交時(shí)生成的,我們還是把它稱為事務(wù)提交號(hào)更容易理解一些。

只有 update undo 段需要事務(wù)提交號(hào)。purge 線程清理 update undo 日志時(shí),會(huì)根據(jù) update undo 段的 undo 日志組中保存的事務(wù)提交號(hào),決定是否能清理這個(gè) undo 日志組中的 undo 日志。

修改 update undo 段的狀態(tài)之前,InnoDB 會(huì)生成事務(wù)提交號(hào),保存到事務(wù)對(duì)象的 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() 調(diào)用 trx_sys_allocate_trx_id_or_no() 生成事務(wù)提交號(hào)。

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

從上面的代碼可以看到,生成事務(wù) ID 和事務(wù)提交號(hào)調(diào)用的是同一個(gè)方法,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() 每次被調(diào)用
  // 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 保存的是下一個(gè)事務(wù) ID 或事務(wù)提交號(hào),具體是哪個(gè),取決于是生成事務(wù) ID 還是生成事務(wù)提交號(hào)先調(diào)用 trx_sys_allocate_trx_id_or_no()。

也就是說,事務(wù) ID 和事務(wù)提交號(hào)是同一條流水線上生產(chǎn)出來的。我們以 trx 1 和 trx 2 兩個(gè)事務(wù)為例,來說明生成事務(wù) ID 和事務(wù)提交號(hào)的流程。

假設(shè)此時(shí) trx_sys->next_trx_id_or_no 的值為 100,trx 1、trx 2 啟動(dòng)和提交的順序如下:

  • trx 1 啟動(dòng)。
  • trx 2 啟動(dòng)。
  • trx 1 提交。
  • trx 2 提交。

其于以上假設(shè),生成事務(wù) ID 和事務(wù)提交號(hào)的流程如下:

  • trx 1 生成事務(wù) ID,得到 100。trx_sys->next_trx_id_or_no 加 1,結(jié)果為 101。
  • trx 2 生成事務(wù) ID,得到 101。trx_sys->next_trx_id_or_no 加 1,結(jié)果為 102。
  • trx 1 生成事務(wù)提交號(hào),得到 102。trx_sys->next_trx_id_or_no 加 1,結(jié)果為 103。
  • trx 2 生成事務(wù)提交號(hào),得到 103。trx_sys->next_trx_id_or_no 加 1,結(jié)果為 104。

從以上流程可以看到,事務(wù) ID 和事務(wù)提交號(hào)都來源于 trx_sys->next_trx_id_or_no,相互之間不會(huì)重復(fù)。

2.3 修改 update undo 段狀態(tài)

如果事務(wù)更新或刪除了用戶普通表的記錄,InnoDB 會(huì)為事務(wù)分配一個(gè) update undo 段。

如果事務(wù)更新或刪除了用戶臨時(shí)表的記錄,InnoDB 會(huì)為事務(wù)分配另一個(gè) update undo 段。

InnoDB 可能會(huì)給事務(wù)分配 0 ~ 2 個(gè) update undo 段。commit 子階段會(huì)修改分配給事務(wù)的所有 update undo 段的狀態(tài)。

如果 update undo 段滿足緩存條件,它的狀態(tài)會(huì)被修改為 TRX_UNDO_CACHED,否則,它的狀態(tài)會(huì)被修改為 TRX_UNDO_TO_PURGE。

2.4 undo 日志組加入 history list

修改完 update undo 段的狀態(tài),update undo 段的 undo 日志組會(huì)加入回滾段的 history list 鏈表。purge 線程會(huì)從這個(gè)鏈表中獲取要清理的 undo 日志組。

前面已經(jīng)生成了事務(wù)提交號(hào),這里會(huì)把事務(wù)提交號(hào)寫入 undo 日志組的頭信息中。

如果 update undo 段的狀態(tài)為 TRX_UNDO_CACHED,表示這個(gè) undo 段需要緩存起來。它會(huì)加入回滾段的 update_undo_cached 鏈表頭部,以備后續(xù)其它事務(wù)需要 update undo 段時(shí),能夠快速分配。

3. InnoDB 提交事務(wù)完成

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

現(xiàn)在,要把事務(wù)狀態(tài)修改為 TRX_STATE_COMMITTED_IN_MEMORY。

修改之后,新啟動(dòng)的事務(wù)就能看到該事務(wù)插入或更新的記錄,看不到當(dāng)前事務(wù)刪除的記錄。

接下來,InnoDB 會(huì)釋放事務(wù)執(zhí)行過程中加的表鎖、記錄鎖。

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

如果 insert undo 段的狀態(tài)為 TRX_UNDO_CACHED,表示這個(gè) undo 段需要緩存起來。它會(huì)加入回滾段的 insert_undo_cached 鏈表頭部,以備后續(xù)其它事物需要 insert undo 段時(shí),能夠快速分配。

如果 insert undo 段的狀態(tài)為 TRX_UNDO_TO_FREE,它會(huì)被釋放,占用的 undo 頁會(huì)還給 undo 表空間。

二階段提交的 flush 子階段,已經(jīng)把 prepare 階段及之前產(chǎn)生的 redo 日志都刷盤了。

commit 子階段,修改 insert undo 段和 update undo 段的狀態(tài),還會(huì)產(chǎn)生 redo 日志。

InnoDB 不會(huì)主動(dòng)觸發(fā)操作系統(tǒng)把這些 redo 日志刷盤,而是由操作系統(tǒng)決定什么時(shí)候把這些 redo 日志刷盤。

InnoDB 敢這么做,是因?yàn)檫@些 redo 日志對(duì)于確定事務(wù)狀態(tài)已經(jīng)不重要了。即使這些 redo 日志刷盤之前,服務(wù)器突然異常關(guān)機(jī),導(dǎo)致 undo 段的狀態(tài)丟失。MySQL 下次啟動(dòng)時(shí),也能正確的識(shí)別到事務(wù)已經(jīng)提交完成了。

4. 重新初始化事務(wù)對(duì)象

到這里,InnoDB 提交事務(wù)該做的操作都已經(jīng)做完了。提交事務(wù)完成之后,該做的事也都做了。

對(duì)于上一個(gè)事務(wù),事務(wù)對(duì)象的使命已經(jīng)結(jié)束。這里會(huì)把事務(wù)狀態(tài)修改為 TRX_STATE_NOT_STARTED。

事務(wù)對(duì)象也會(huì)被重新初始化,但是它不會(huì)被釋放。也就是說,事務(wù)對(duì)象不會(huì)回到事務(wù)池中,而是留給當(dāng)前連接后續(xù)啟動(dòng)新事務(wù)時(shí)復(fù)用。

5. 總結(jié)

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

第 1 件,修改分配給事務(wù)的各 undo 段的狀態(tài)。

如果數(shù)據(jù)庫發(fā)生崩潰,重新啟動(dòng)后,undo 段的狀態(tài)是影響事務(wù)提交還是回滾的因素之一。

第 2 件,修改事務(wù)對(duì)象的狀態(tài)。

如果數(shù)據(jù)據(jù)庫一直運(yùn)行,不發(fā)生崩潰,就靠事務(wù)對(duì)象的狀態(tài)來標(biāo)識(shí)事務(wù)是否已提交。

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

其它事務(wù)都不再需要使用這些 undo 日志時(shí),后臺(tái) purge 線程會(huì)清理這些 undo 日志組中的日志。

責(zé)任編輯:武曉燕 來源: 愛可生開源社區(qū)
相關(guān)推薦

2024-04-03 08:20:53

MySQL核心模塊

2024-05-15 09:05:42

MySQL核心模塊

2024-06-05 11:49:33

2023-12-08 08:38:15

EventLoopAPI瀏覽器

2024-01-08 20:05:32

2023-06-09 07:18:03

開源數(shù)據(jù)庫

2024-05-30 08:19:52

微服務(wù)架構(gòu)大型應(yīng)用

2024-01-25 09:10:10

GoRust標(biāo)準(zhǔn)庫

2023-05-11 08:14:58

國(guó)產(chǎn)數(shù)據(jù)庫用戶

2024-08-28 08:50:11

MySQL核心模塊

2023-12-26 07:37:27

2023-06-14 17:56:54

2024-08-28 13:09:50

2022-12-30 08:35:00

2023-04-26 00:00:00

框架Vue.js客戶

2024-08-07 14:58:00

MySQL釋放鎖核心模塊

2023-06-08 09:55:03

冪等計(jì)算機(jī)系統(tǒng)

2022-10-10 18:38:56

inert屬性鍵盤

2022-04-07 11:15:22

PulseEventAPI函數(shù)

2023-12-28 08:43:28

前端算法搜索
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)