精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Undo 日志用什么存儲結構支持無鎖并發寫入?

數據庫 MySQL
本文我們就來聊聊 undo 日志的存儲結構,它是怎么寫入 undo 日志文件的,以及事務二階段提交過程中和它有關的操作。

redo 日志只有崩潰恢復的時候才能派上用場,undo 日志不一樣,它承擔著多重職責,MySQL 崩潰恢復、以及正常提供服務期間,都有它的身影。

按照使用頻次,undo 日志的多重職責如下:

職責 1,為 MVCC 服務,減少讀寫事務之間的相互影響,提升數據庫的并發能力。

職責 2,保證數據庫運行過程中的數據一致性。事務回滾時,把事務中被修改的數據恢復到修改之前的狀態。

職責 3,保證數據庫崩潰之后的數據一致性。崩潰恢復過程中,恢復沒有完成提交的事務,并根據事務的狀態和 binlog 日志是否寫入了該事務的 xid 信息,共同決定事務是提交還是回滾。

undo 日志需要為數據一致性和 MVCC 服務,除了要支持多事務同時寫入日志,還要支持多事務同時讀取日志。

為了有更好的讀寫并發性能,它擁有與 redo 日志完全不一樣的存儲結構。

本文我們就來聊聊 undo 日志的存儲結構,它是怎么寫入 undo 日志文件的,以及事務二階段提交過程中和它有關的操作。

本文內容基于 MySQL 8.0.29 源碼。

正文

1、 概述

undo 日志的存儲結構比較復雜,我們先以倒序的方式來介紹一下存儲結構的各個部分,以便大家有個整體了解。

undo log header:一個事務可能產生多條 undo 日志,也可能只產生一條 undo 日志,不管事務產生了多少條 undo 日志,這些日志都歸屬于事務對應的日志組,日志組由 undo log header 負責管理。

undo 頁:undo log header 和 undo 日志都存儲于 undo 頁中。

undo 段:為了多個事務同時寫 undo 日志不相互影響,undo 日志也使用了無鎖設計,InnoDB 會為每個事務分配專屬的 undo 段,每個事務只會往自己專屬 undo 段的 undo 頁中寫入日志。

一個 undo 段可能會包含一個或多個 undo 頁,多個 undo 頁會形成 undo 頁面鏈表。

inode:每個 undo 段都會關聯一個 inode。

undo 段本身并不具備管理 undo 頁的能力,有了 inode 這個外掛之后,undo 段就可以管理段中的 undo 頁了。

回滾段:一個事務可能會需要 1 ~ 4 個 undo 段,很多個事務同時執行,就需要很多個 undo 段,這些 undo 段需要有一個地方統籌管理,這個地方就是回滾段。

undo slot:一個回滾段管理著 1024 個 undo 段,每個回滾段的段頭頁中都有 1024 個小格子,用來記錄 undo 段中第一個 undo 頁的頁號,這個小格子就叫作 undo slot。

重要說明: 一個回滾段管理 1024 個 undo 段,這是基于 innodb_page_size 是 16K(默認值) 的情況,本文涉及到頁大小的內容,都以 16K 的頁為前提,后面就不再單獨說明了。

undo 表空間:一個回滾段能夠管理 1024 個 undo 段,看起來已經很多了,假設每個事務都只需要 1 個 undo 段,如果只有一個回滾段也只能支持 1024 個事務同時執行。

對于擁有幾十核甚至百核以上 CPU 的服務器來說,這顯然會限制它們的發揮。

為了充分發揮服務器的能力,有必要支持更多事務的同時執行,所以就有了 undo 表空間,一個 undo 表空間最多可以支持 128 個回滾段。

不止于此,InnoDB 還能夠最多支持 127 個 undo 表空間,這樣算起來,所有回滾段總共能夠管理的 undo 段數量是:1024 * 128 * 127 = 16646144。

這么多 undo 段,是不是瞬間就有了地主家有余糧的感覺?

圖片

看了上面的介紹,相信大家能對 undo 日志有個整體了解,接下來我們就按照這個整體結構,自頂向下來詳細介紹其中的每個部分。

2、undo 表空間

一個獨立的 undo 表空間對應磁盤上的一個文件。

MySQL 8.0 開始,強制開啟了獨立的 undo 表空間,支持創建 2 ~ 127 個 undo 表空間,默認數量為 2,可以通過 CREATE UNDO TABLESPACE 增加 undo 表空間,通過 DROP UNDO TABLESPACE 減少 undo 表空間。

每個 undo 表空間都可以配置 1 ~ 128 個回滾段,可以通過系統變量 innodb_rollback_segments 來控制每個 undo 表空間中的回滾段數量,默認值為 128。

每個 undo 表空間中,page_no = 3 的頁專門用于保存回滾段的段頭頁的頁號,這個頁的類型是 FIL_PAGE_TYPE_RSEG_ARRAY,從 Offset 56 開始,保存著 128 個回滾段的段頭頁的頁號,如下圖所示:

圖片

圖片

3、回滾段

(1)什么是回滾段?

InnoDB 中凡是被稱為段的東西,都是用來管理數據頁的一種邏輯結構。

回滾段也不例外,它也是管理數據頁的一種邏輯結構。

回滾段管理了什么頁呢?

回滾段有一點點特殊,它只管理一個頁,就是回滾段的段頭頁。

每個回滾段中只有段頭頁這一個數據頁,由此可見,管理數據頁并不是它最重要的職責。

在概述小節,我們介紹過,每個回滾段中都有 1024 個 undo slot,可以統籌管理 1024 個 undo 段,這才是回滾段最重要的職責。

基于前面的介紹,我們可以給回滾段下一個定義了:回滾段是一種邏輯結構,它負責段頭頁的分配,以及管理其中 1024 個 undo slot 對應的 undo 段。

(2)分配回滾段

開啟一個讀寫事務,或者一個只讀事務轉換為讀寫事務時,InnoDB 會為事務分配一個回滾段。

默認配置下,2 個 undo 表空間總共有 256 個回滾段,這么多回滾段,就涉及到怎么均衡使用的問題了。

2 個 undo 表空間,在內存是中一個數組,下標分別為 0、1。

每個 undo 表空間中 128 個回滾段,在內存中也是一個數組,下標為 0 ~ 127。

以 undo 表空間下標、回滾段下標組成一個元組,用于表示默認配置下的 256 個回滾段,如下:

(0, 0)、(0, 1)、…、(0, 126)、 (0, 127)

(1, 0)、(1, 1)、…、(1, 126)、 (1, 127)

分配回滾段的邏輯是按照 undo 表空間、回滾段輪流著來,順序是這樣的:

(0, 0)、(1, 0)、(0, 1)、(1, 1)、……、(0, 126)、(1, 126)、(0, 127)、(1, 127)

分配順序用圖片展示是這樣的(按照箭頭順序分配):

圖片

每次分配時,都會記錄這次分配的是哪個回滾段。

下次再分配時,按照上面的順序,把最后一次分配的回滾段之后的那個回滾段分配給事務。

InnoDB 中的回滾段,分為普通表回滾段、用戶臨時表回滾段,前面介紹的是普通表回滾段分配邏輯。

用戶臨時表只有一個獨立 undo 表空間,默認 128 個回滾段,需要分配臨時表回滾段時,只要輪流分配就行了。

4、undo slot

(1)什么是 undo slot?

每個回滾段的段頭頁中都有 1024 個小格子,每個小格子就是一個 undo slot,用于記錄分配給事務的 undo 段的段頭頁頁號,如下圖所示:

圖片圖片

(2)尋找 undo slot

一條 DML 語句即將要修改數據之前,會先記錄 undo 日志。

記錄 undo 日志之前,需要先創建一個 undo 段。

undo 段要把自己交給回滾段管理,這需要在回滾段的段頭頁中找一個 undo slot 占個位。

尋找 undo slot 的過程簡單粗暴,從回滾段 1024 個 slot 中的第一個 slot 開始遍歷,讀取 slot 的值,只要 slot 的值等于 FIL_NULL,就說明這個 slot 沒有被別的 undo 段占用,當前 undo 就可以占上這個位置。

FIL_NULL 是 32 位無符號整數的最大值,十六進制表示為 0xFFFFFFFFUL,十進制表示為 4294967295。

如果遍歷到最后一個 slot,都沒有發現 值 = FIL_NULL 的 slot,那就說明分配給當前事務的回滾段沒有可用的 slot 了。

這種情況下,InnoDB 并不會再重新給事務分配一個回滾段,而是直接報錯:Too many active concurrent transactions。

5、undo 段

(1)什么是 undo 段?

undo 段,也是段字輩,那它自然也是管理數據頁的一種邏輯結構了。

undo 段管理的數據頁就是用來存放 undo 日志的頁,也就是 undo 頁。

按照對于表的增、刪、改操作是否需要記錄 redo 日志來分類,undo 段可以分為 2 種類型:

臨時表 undo 段,對于用戶臨時表的增、刪、改操作,數據庫崩潰之后重新啟動,不需要恢復這些表里的數據,也就是說臨時表里的數據不需要保證持久性,因此不需要記錄 redo 日志。

但是,如果事務對用戶臨時表進行了增、刪、改操作,事務回滾時,用戶臨時表中的數據也需要回滾,所以需要記錄 undo 日志。

普通表 undo 段,對于普通表的增、刪、改操作,數據庫崩潰之后重新啟動,需要把這些操作修改過的數據,恢復到數據庫崩潰時的狀態,所以需要記錄 redo 日志。

事務回滾時,對于普通表進行的增、刪、改操作,表中的數據也需要回滾,所以需要記錄 undo 日志。

按照增、刪、改操作來分類,undo 段也可以分為 2 種類型:

  • insert undo 段,用于保存 insert 語句產生的 undo 日志的 undo 段。
  • update undo 段,用于保存 update、delete 語句產生的 undo 日志的 undo 段。

為什么要區分 insert undo 段和 update undo 段?

因為 insert 語句產生的 undo 日志,在事務提交時,如果 undo 段不能被緩存起來復用,就會直接釋放。

update、delete 語句產生的 undo 日志,在事務提交時,如果 undo 段不能被緩存起來復用,也不會直接釋放,而是要服務于 MVCC。

等到 undo 日志中的歷史版本數據不再被其它事務需要時,這些 undo 日志才能被清除。

關于 undo 日志什么時候能被清除的細節,留到 purge 線程清理 undo 日志的文章再寫。

此時,如果 undo 日志所在的 undo 段中沒有其它有效的 undo 日志時,undo 段才能被釋放。

按照前面的 2 種維度分類,可以形成 4 種類型的 undo 段:

  • 插入記錄到用戶臨時表,是臨時表 insert undo 段。
  • 更新、刪除用戶臨時表中的記錄,是臨時表 update undo 段。
  • 插入記錄到普通表,是普通表 insert undo 段。
  • 更新、刪除普通表中的記錄,是普通表 update undo 段。

在同一個事務中,以上 4 種類型的 undo 段都有可能出現,所以,一個事務中就可能會需要  1 ~ 4 個 undo 段。

(2)復用緩存的 undo 段

每創建一個 undo 段,需要經過一系列的操作:

  • 從 inode 頁中找到一個未被使用的 inode。
  • 分配一個 inode 頁(可能需要)。
  • 為 undo 段分配一個 undo 頁。
  • 初始化內存中的 undo 段對象。
  • 初始化內存中的 undo log header 對象。
  • 其它操作 ...

這些初始化操作都是需要時間的,頻繁創建就有點浪費時間了。為此,InnoDB 設定了一個規則,在事務提交時,符合規則的 undo 段就可以被緩存起來,給后面的事務重復使用。

undo 段可緩存復用的規則,本文后面二階段提交的 commit 階段會介紹。

前面介紹過,事務中使用 undo 段時,按照 2 種維度分類會形成 4 種類型的 undo 段,這是不是有點復雜?

undo 段緩存就比較簡單了,只分了 2 種:insert undo 段、update undo 段。

有了 undo 段緩存之后,就不需要每次分配 undo 段時都從頭開始創建一個了。

如果要為用戶臨時表、普通表的 insert 語句分配一個 undo 段,就去 insert_undo_cached 鏈表中(緩存 insert undo 段的鏈表)看看有沒有 undo 段可以復用。

如果有,就取鏈表中的第一個 undo 段來用;如果沒有,就創建一個新的 insert undo 段。

如果要為用戶表、普通表的 update、delete 語句分配一個 undo 段,就去 update_undo_cached 鏈表中(緩存 update undo 段的鏈表)看看有沒有 undo 段可以復用。

如果有,就取鏈表中的第一個 undo 段來用;如果沒有,就創建一個新的 update undo 段。

(3)創建 undo 段

InnoDB 給事務分配一個 undo 段時,如果沒有緩存的 undo 段可以復用,需要創建一個新的 undo 段。

創建一個新的 undo 段,會經歷以下幾個主要步驟:

第 1 步,找到一個 inode,undo 段會關聯一個 inode,用于管理段中的頁。

inode 后面會有一個小節單獨介紹,這里先不展開。

第 2 步,從表空間 0 號頁的 File Space Header 中讀取 FSP_SEG_ID,作為新創建的 undo 段的 ID(seg_id),把 seg_id 寫入 inode 的 FSEG_ID 字段,表示這個 inode 已經被占用了。

第 3 步,通過 inode 分配一個新的空閑頁作為 undo 段的段頭頁。

每個 undo 段都會有一個 Undo Segment Header,位于 undo 段的段頭頁中,如下圖所示:

圖片圖片

第 4 步,把 inode 的地址信息寫入 Undo Segment Header 的 TRX_UNDO_FSEG_HEADER 字段。

inode 的地址由 3 個部分組成:

  • inode 所在頁的表空間 ID。
  • inode 所在頁的頁號。
  • inode 在頁中的 Offset。

第 5 步,把段頭頁加入 undo 頁面鏈表的最后,undo 頁面鏈表的基結點位于 Undo Segement Header 的 TRX_UNDO_PAGE_LIST 字段中。

第 6 步,把 undo 段的段頭頁頁號寫入回滾段中分配給當前 undo 段的 undo slot 中,表示這個 undo slot 被占用了。

經過以上步驟后,undo 段就創建成功了,可以繼續進行接下來的操作了。

6、undo log header

(1)什么是 undo log header?

一個事務產生的 undo 日志屬于一個日志組,undo log header 是日志組的頭信息,各字段如下圖所示:

圖片

介紹幾個主要字段:

  • TRX_UNDO_TRX_ID,產生這組 undo 日志的事務 ID。
  • TRX_UNDO_TRX_NO,事務的提交號,事務提交時會修改這個字段的值。
  • TRX_UNDO_NEXT_LOG,undo 段中下一組 undo 日志的 undo log header 在頁中的 Offset。
  • TRX_UNDO_PREV_LOG,undo 段中上一組 undo 日志的 undo log header 在頁中的 Offset。
  • TRX_UNDO_HISTORY_NODE?,表示這組 undo 日志是 history 鏈表的一個結點,purge 線程清理 TRX_UNDO_UPDATE 類型的 undo 日志時會用到這個字段。

(2)復用 undo log header

如果分配給事務的 insert undo 段,是從 insert_undo_cached 鏈表中獲取的,undo 段中的 undo log header 是可以直接復用的,但是其中 4 個字段需要重新初始化:

  • TRX_UNDO_TRX_ID,寫入新的事務 ID。
  • TRX_UNDO_LOG_START,重置為 undo log header 之后的位置,表示可以寫 undo 日志的位置。
  • TRX_UNDO_FLAGS,undo 日志組的標記重置為 0。
  • TRX_UNDO_DICT_TRANS,表示當前這組 undo 日志是否由 DDL 語句事務產生。

由于 update undo 段中的 undo 日志未被清理之前都需要為 MVCC 服務,如果分配給事務的 update undo 段是復用的 undo 段,不能復用其中的 undo log header,而是會生成一個新的 undo log header,追加到上一個事務生成的 undo 日志之后的位置。

(3)創建 undo log header

新創建一個 insert / update undo 段,或者復用一個 update undo 段時,都需要創建一個 undo log header。

創建一個新的 undo log header,就是把 undo log header 中的每個字段值按順序寫入 undo 頁中,然后在內存中也會生成一個對應的結構(struct trx_undo_t),并初始化其中的各個字段。

需要單獨拿出來說的字段有兩個:

  • TRX_UNDO_PREV_LOG?,指向 update undo 段中上一個事務生成的 undo 日志在 update undo 段的段頭頁中的 Offset。
  • TRX_UNDO_NEXT_LOG?,指向 update undo 段下一個事務生成的 undo 日志在 update undo 段的段頭頁中的 Offset。

通過這兩個字段,update undo 段中的多組 undo 日志就形成了鏈表,purge 線程清理 undo 日志時就可以通過鏈表找到 undo 頁中的所有 undo 日志了。

7、inode

(1)什么是 inode?

不管是回滾段、undo 段,還是索引段,只要是段,都會關聯一個 inode。

inode 是真正用于管理與它關聯的段中數據頁的邏輯結構,undo 段之所以能夠管理其中的 undo 頁,關鍵就是因為 undo 段關聯了 inode。

inode 結構如下圖所示:

圖片

由上圖可見,inode 中有 32 個 fragment page slot,可以管理 32 個碎片頁。

還有 3 個以 extent 為單位管理數據頁的鏈表:

頁大小為 16K 時,1 個 extent 中有 64 個頁。

  • FSEG_FREE,這個鏈表的每個 extent 中,所有頁都沒有被使用,全都是空閑頁。
  • FSEG_NOT_FULL,這個鏈表的每個 extent 中,都有一部分頁已被使用,另一部分頁是空閑頁。
  • FSEG_FULL,這個鏈表的每個 extent 中,所有頁都已經被使用,沒有空閑頁。

根據頁的分配規則,inode 關聯的段每分配一個頁,既有可能從 32 個 fragment page slot 中找一個空閑頁,也有可能從 FSEG_FREE、FSEG_NOT_FULL 中找一個空閑頁。

(2)分配 inode

undo 表空間中,有專門的 inode 頁用于存放 inode,每個 inode 占用 192 字節,16K 的 inode 頁最多能夠存放 85 個 inode,如下圖所示:

圖片圖片

undo 表空間 0 號頁的 File Space Header 中,有 2 個管理 inode 頁的鏈表:

  • FSP_SEG_INODES_FULL,這個鏈表中的所有 inode 頁都存放了 85 個 inode,不能再存入新的 inode。
  • FSP_SEG_INODES_FREE,這個鏈表中的所有 inode 頁都還有空閑空間可以存入新的 inode。

File Space Header 中的各字段如下圖所示:

圖片

每次為事務創建一個新的 undo 段之前,都會先從 FSP_SEG_INODES_FREE 鏈表的第一個 inode 頁中獲取一個可用的 inode。

從 inode 頁中獲取 inode 的邏輯簡單粗暴:

從 inode 頁中的第一個 inode 開始遍歷,直到找到一個 FSP_SPACE_ID 字段值為 0 的 inode,表示這個 inode 未被其它 undo 段占用,可以分配給當前 undo 段。

不過,有可能會出現一個意外情況,就是 FSP_SEG_INODES_FREE 鏈表中沒有可用的 inode 頁。

這種情況下,需要先從 undo 表空間中分配一個碎片頁,用作 inode 頁,然后再按照前面介紹的分配 inode 邏輯,給當前 undo 段分配一個 inode。

8、寫 undo 日志

本文不會詳細介紹 undo 日志的格式,但是,每一種類型的 undo 日志中,都有 2 個字段,用于把 undo 日志組中的多條日志組成日志鏈表,需要介紹一下。

每一條 undo 日志中,第一個字段是 next_record_start,占用 2 字節,保存著下一條 undo 日志的第一個字節在 undo 頁中的 Offset。

每一條 undo 日志中,最后一個字段是 record_start,占用 2 字節,保存著當前這條 undo 日志第一個字節在 undo 頁中 Offset。

next_record_start、record_start 是為了描述方便而取的名字。

通過這 2 個字段,同一個 undo 頁中的多條 undo 日志可以形成一個雙向鏈表,如下圖所示:

圖片圖片

從前往后遍歷 undo 日志時,通過 next_record_start 就可以直接讀取到下一條 undo 日志的 Offset 了。

從后往前遍歷  undo 日志時,通過 record_start 只能讀取到本條日志的 Offset,再讀取本條日志的 Offset - 2 處的字段內容,就能得到上一條 undo 日志的 Offset 了。

為什么要把 next_record_start 作為 undo 日志的第一個字段,record_start 作為 undo 日志的最后一個字段?

我第一次看到 undo 日志的這個結構,是在看《MySQL 是怎樣運行的》這本書的時候,當時感覺這樣的結構很不好理解。

研究完源碼寫本文的時候,我試圖為這個結構找到一個合理的解釋,以方便大家理解。

但是,想了幾種不使用這個結構可能會帶來的壞處(例如:占用更多存儲空間,遍歷 undo 日志的時候需要更多時間等等),都沒有找到必須要這樣設計的合理解釋。

所以,大家也不用糾結為什么會這樣設計,就當它是個普通的鏈表指針就好了。

當然了,如果有哪位小伙伴發現了這么設計的好處,也歡迎在文末留言或者微信交流。

正常寫入 undo 日志的過程比較簡單:

  • 先寫 undo 日志數據。
  • 再寫 next_record_start、record_start 在其所處 undo 頁中的 Offset。

undo 日志是每產生一條就往 undo 日志文件中寫入一條(只是寫到 Buffer Pool 中 undo 頁,由刷盤操作統一刷新到磁盤)。

寫 undo 日志中每個字段的細節就不再展開了。

寫 undo 日志的過程中可能會面臨一個臨界點:

前面我們提到過,undo 段是可以復用的,對于復用的 insert undo 段,邏輯比較簡單,直接覆蓋 undo 段中原來的日志數據就可以了。

對于復用的 update undo 段,由于其中的 undo 日志還需要為 MVCC 服務,不能被覆蓋,需要把新的 undo 日志追加到原來的 undo 日志之后。

這樣一來就可能會出現 2 種情況:

情況 1,undo 頁中剩余空間足夠寫入一條新的 undo 日志,這種情況就簡單了,直接把新的 undo 日志寫入 undo 頁中剩余的空間。

情況 2,undo 頁中剩余空間不夠寫入一條新的 undo 日志了,這種情況稍微復雜點,會分三步進行:

  • 把 undo 頁中剩余空間的所有字節全部填充為0xff。
  • 創建一個新的 undo 頁。
  • 把 undo 日志寫入到新的 undo 頁中。

還有一種不應該出現的情況:

由于一條 undo 日志內容太長,一個空閑的 undo 頁都存不下一條 undo 日志。

正常情況下不會發生這樣的事情,只有 MySQL 源碼有 bug 的時才會出現。

text、blob 系列大字段,存儲的內容長度可能超過 undo 頁的大小,更新操作的 undo 日志有可能會超過 undo 日志的大小嗎?

如果源碼沒 bug 的話,不會超過的,對于 text、blob 系列大字段,記錄 undo 日志時并不是直接把字段內容原封不動的寫到 undo 日志里,而是會做一些處理,只會有少量內容寫到 undo 日志里。

關于 text、blob 系列大字段具體會往 undo 日志里寫入什么,如果有小伙伴感興趣,可以留言或者微信交流,后續我可以再進一步研究這些細節,然后寫篇文章單獨介紹。

9、階段提交之 undo 日志

(1)prepare 階段

在 prepare 階段,undo 日志為事務做的最重要的 2 件事:

  • 修改 undo 段狀態,把 Undo Segement Header 的 TRX_UNDO_STATE? 字段值從 TRX_UNDO_ACTIVE 修改為 TRX_UNDO_PREPARED?,表示 undo 日志對應的事務已經進入 prepare 階段。
  • 把事務 xid 信息寫入 Undo log Header 中。

undo 段狀態用于崩潰恢復過程中,標記哪些事務需要恢復,哪些事務不用恢復。

xid 信息用于崩潰恢復過程中,決定數據庫崩潰時處于 prepared 階段的事務,是要回滾還是要提交。

(2)commit 階段

到了 commit 階段,insert undo 日志的使命就已經結束了,update undo 日志還需要為 MVCC 服務。

不管是 insert undo 段還是 update undo 段,只要滿足以下 2 個條件都可以被緩存起來復用:

  • undo 段中只有一個 undo 頁。
  • 包括 File Header、Page Header 在內,undo 頁已使用空間必須小于 undo 頁總字節數的四分之三。

對于 insert undo 段,如果能復用,會進行以下操作:

步驟 1,Undo Segment Header 的 TRX_UNDO_STATE 字段值由 TRX_UNDO_PREPARED 變為 TRX_UNDO_CACHED。

步驟 2,事務對應 undo 日志組的 undo log header 對象加入回滾段 insert_undo_cached 鏈表的最前面,以備下一個事務復用。

如果不能復用,會進行以下操作:

步驟 1,Undo Segement Header 的 TRX_UNDO_STATE 字段值由 TRX_UNDO_PREPARED 變為 TRX_UNDO_TO_FREE。

步驟 2,undo 段關聯的 inode 的 FSEG_ID 字段改為 0,表示 inode 可以被其它 undo 段使用,然后釋放 undo 段中分配的所有 undo 頁。

步驟 3,把 insert undo 段占用的 undo slot 值會改為 FIL_NULL,表示這個 undo slot 處于空閑狀態,可以被其它事務使用了。

對于 update undo 段,如果能復用,會進行以下操作:

步驟 1,Undo Segment Header 的 TRX_UNDO_STATE 字段值由 TRX_UNDO_PREPARED 變為 TRX_UNDO_CACHED。

步驟 2,通過 undo log header 字段 TRX_UNDO_HISTORY_NODE 把 undo 日志組加入 history list 鏈表。

purge 線程通過遍歷 history list 鏈表來清除 undo 日志。

步驟 3,把事務提交號寫入 undo log header 字段 TRX_UNDO_TRX_NO。

purge 線程用這個字段來判斷 undo 日志是否能夠被清除、標記刪除的記錄是否能夠徹底刪除。

步驟 4,事務對應 undo 日志組的 undo log header 對象加入回滾段 update_undo_cached 鏈表的最前面,以備下一個事務復用。

如果不能復用,會進行以下操作:

步驟 1,Undo Segement Header 的 TRX_UNDO_STATE 字段值由 TRX_UNDO_PREPARED 變為 TRX_UNDO_TO_PURGE。

步驟 2,update undo 段占用的 undo slot 的值改為 FIL_NULL,表示這個 undo slot 處于空閑狀態,可以被其它事務使用了。

步驟 3,從回滾段 Rollback Segnemt Header 中讀取 TRX_RSEG_HISTORY_SIZE,加上 undo 段中 undo 頁的數量,然后回寫到 TRX_RSEG_HISTORY_SIZE 中,作為 history list 鏈表中最新的 undo 頁數量。

undo 能夠復用時,不會修改 TRX_RSEG_HISTORY_SIZE 字段值。

步驟 4,通過 undo log header 字段 TRX_UNDO_HISTORY_NODE 把 undo 日志組加入 history list 鏈表。

purge 線程通過遍歷 history list 鏈表來清除 undo 日志。

步驟 5,把事務提交號寫入 undo log header 字段 TRX_UNDO_TRX_NO。

purge 線程用這個字段來判斷 undo 日志是否能夠被清除、標記刪除的記錄是否能夠徹底刪除。

小結一下,commit 階段,就是 undo 段能復用就復用,不能復用就直接清理釋放(insert undo 段),或者等待 purge 線程清理釋放(update undo 段)。

10、總結

InnoDB 支持 2 ~ 127 個獨立表空間,每個表空間支持 1 ~ 128 個回滾段,每個回滾段支持 1024 個 undo slot,可以管理 1024 個 undo 段。

undo 段可以分為 4 種類型:臨時表 insert undo 段、臨時表 update undo 段、普通表 insert undo 段、普通表 update undo 段。

如果 undo 段中只有 1 個 undo 頁,并且 undo 頁中已使用空間小于 undo 頁大小的四分之三,undo 段可以被緩存起來復用。

可以復用的 insert undo 段緩存到 insert_undo_cached 鏈表,可用復用的 update undo 段緩存到 update_undo_cached 鏈表。

每個 undo 段都會關聯一個 inode,用于管理段中的頁,inode 存放于表空間的 inode 頁中。

一個事務產生的一條或多條 undo 日志會形成一個日志組,日志組由 undo log header 負責管理。

多條 undo 日志通過日志中的 next_record_start、record_start 形成雙向鏈表。

寫 undo 日志時,如果復用的 update undo 段的段頭頁中剩余空間不夠存放一條 undo 日志時,會分配一個新的 undo 頁,并把 undo 日志寫入到新的 undo 頁中。

本文轉載自微信公眾號「一樹一溪」,可以通過以下二維碼關注。轉載本文請聯系一樹一溪公眾號。

責任編輯:姜華 來源: 一樹一溪
相關推薦

2019-11-11 15:33:34

高并發緩存數據

2019-08-14 15:08:51

緩存存儲數據

2020-12-21 09:57:33

無鎖緩存并發緩存

2023-05-09 08:28:44

Go語言并發編程

2021-05-07 08:00:00

數據中心無服務器架構

2024-02-29 09:44:36

Java工具

2020-07-07 07:47:07

Java無鎖技術

2025-09-28 04:00:00

2024-05-28 00:10:00

JavaMySQL數據庫

2019-11-28 16:00:06

重入鎖讀寫鎖樂觀鎖

2024-01-25 10:23:22

對象存儲存儲數據

2022-01-10 23:54:56

GoMap并發

2025-04-28 02:22:00

2021-12-15 07:49:22

Go語言設計

2022-10-12 08:01:08

MySQL日志數據庫

2020-01-15 09:53:59

MySQL緩存索引

2010-04-21 16:07:04

Oracle邏輯存儲結

2025-11-18 01:00:00

2021-07-13 07:02:03

prometheus監控遠端服務

2019-06-03 15:15:09

MySQL索引數據庫
點贊
收藏

51CTO技術棧公眾號

污版视频在线观看| 91在线无精精品一区二区| av免费观看不卡| 天堂中文在线播放| 国产欧美日韩视频在线观看| 国产专区欧美专区| 国产精品第九页| 精品久久久久久久| 日韩网站在线看片你懂的| 欧美一区二区中文字幕| av中文字幕在线| 精品一区二区三区在线视频| 国产做受高潮69| 国产黄色片在线| 久本草在线中文字幕亚洲| 欧美视频自拍偷拍| 久久视频这里有精品| 性开放的欧美大片| 91视视频在线观看入口直接观看www | 中文字幕v亚洲ⅴv天堂| 美女又黄又免费的视频| jizz亚洲女人高潮大叫| 亚洲.国产.中文慕字在线| 一本一道久久久a久久久精品91| 亚洲精品国产精品国| 美女久久久精品| 96精品视频在线| 久热精品在线观看| 99久久夜色精品国产亚洲狼| 精品一区二区亚洲| 特级特黄刘亦菲aaa级| 2020国产精品小视频| 91久久精品网| 国产欧美在线一区| 精品极品在线| 亚洲国产一区二区视频| 免费观看中文字幕| 北岛玲一区二区三区| 91片在线免费观看| 高清国产一区| 亚洲AV无码乱码国产精品牛牛 | 91久久偷偷做嫩草影院| 在线免费观看视频网站| 日韩精品成人一区二区在线| 国产91成人video| 日本污视频在线观看| 欧美激情视频一区二区三区在线播放 | 欧美日韩三级一区| www.色就是色| 视频在线日韩| 色乱码一区二区三区88| 欧美污视频网站| 黑人巨大精品欧美一区二区桃花岛| 亚洲高清三级视频| 国产精品国产亚洲精品看不卡| 性欧美videos高清hd4k| 亚洲精品日韩专区silk| 无颜之月在线看| 色噜噜狠狠狠综合欧洲色8| 亚洲美女精品一区| 国产一级片91| 好久没做在线观看| 天天av天天翘天天综合网| 国产不卡一区二区视频| www.51av欧美视频| 日韩欧美成人网| 久草在在线视频| 91大神在线观看线路一区| 欧美三级韩国三级日本三斤| 午夜精品久久久久久久99热影院| 涩涩涩久久久成人精品| 日韩亚洲欧美成人一区| 黑森林av导航| 国产欧美一区二区精品久久久| 一色桃子一区二区| 亚洲熟女毛茸茸| 欧美日本国产| 91成人天堂久久成人| 无码人妻久久一区二区三区不卡| 蜜乳av一区二区| 亚洲一区亚洲二区亚洲三区| 日韩在线观看视频一区二区三区| 久久亚洲春色中文字幕久久久| 色噜噜狠狠一区二区三区| 国产高清视频在线观看| 综合久久久久久久| 久久视频这里有精品| 在线一区视频观看| 日韩欧美自拍偷拍| 亚洲国产无码精品| 国产高清一区| 6080yy精品一区二区三区| 无码人妻av免费一区二区三区| 毛片av一区二区| 国产不卡一区二区在线观看| 国产中文在线视频| 亚洲卡通欧美制服中文| 国内外成人激情视频| 亚洲a成人v| 精品视频偷偷看在线观看| 四虎影视一区二区| 99精品免费视频| 国产精品一区二区三区久久| 狠狠综合久久av一区二区| 国产日韩欧美制服另类| 大胆欧美熟妇xx| 亚洲精品粉嫩美女一区| 精品国产一区二区三区久久久蜜月 | 91免费精品国自产拍在线不卡| 先锋在线资源一区二区三区| 福利在线导航136| 欧美人妖巨大在线| 精品少妇人妻一区二区黑料社区 | 久久男人av| 日韩视频免费大全中文字幕| 中国一级特黄毛片| 国产精品1区二区.| 五月天久久综合网| 涩涩视频网站在线观看| 欧美一卡二卡在线观看| 中文字幕免费视频| 国产欧美日本| 国产91精品一区二区绿帽| 久草免费在线| 欧美色涩在线第一页| 深爱五月激情网| 亚洲日本国产| 国产成人精品一区二区三区福利| 午夜在线视频播放| 在线观看成人免费视频| 无码人妻精品一区二区三区温州 | 神马久久久久久久久久| 亚洲欧美一区二区久久| 久久婷五月综合| 精品一区不卡| 国产成人涩涩涩视频在线观看| 欧美一级淫片aaaaaa| 亚洲精品视频在线| 韩国三级丰满少妇高潮| 综合天堂久久久久久久| 91亚洲精品在线| 黄色成人在线观看| 91精品国产欧美一区二区成人| 精品人体无码一区二区三区| 日韩国产精品91| 欧美日韩在线观看一区| 欧美黑人巨大xxxxx| 亚洲欧美国产精品| 国产伦精品一区二区三区视频我| 久久香蕉国产线看观看99| 99久久久无码国产精品6| 日韩高清在线免费观看| 欧美在线观看网址综合| 日本一二三区在线视频| 色乱码一区二区三区88| 国产成人一区二区在线观看| 奇米四色…亚洲| 亚洲精品一区二| 高清久久一区| 欧美贵妇videos办公室| 黄色av小说在线观看| 精品国产91久久久| 亚洲一区视频在线播放| 秋霞成人午夜伦在线观看| 在线观看欧美一区| 久久久久久亚洲精品美女| 欧美日韩不卡合集视频| 欧美一区二不卡视频| 黑人巨大精品欧美一区二区一视频 | 国产精品久久久久精| 中文字幕精品—区二区四季| 国内国产精品天干天干| 欧美国产高清| 激情久久av| 99欧美精品| 九九热99久久久国产盗摄| 色婷婷av一区二区三区之e本道| 欧美午夜丰满在线18影院| 国产视频三区四区| 国产一区三区三区| 缅甸午夜性猛交xxxx| 日韩欧美一区免费| 成人xxxxx色| 黑人巨大精品欧美一区二区桃花岛| 中文字幕免费精品一区| 国产高清在线免费| 欧美日韩中文字幕日韩欧美| 国产精品麻豆一区| 成人精品在线视频观看| 九热视频在线观看| 国产精品a久久久久| 欧美亚洲精品日韩| 精品国产亚洲一区二区三区| 欧美一级bbbbb性bbbb喷潮片| av免费观看一区二区| 精品日韩欧美在线| 中文字幕日韩第一页| 亚洲第一福利一区| 国产精品久久久久久成人| 国产a级毛片一区| 在线观看免费成人av| 欧美午夜电影在线观看 | 丝袜美腿中文字幕| 国产美女一区二区三区| 国产日韩成人内射视频| 亚洲成人原创| 日本特级黄色大片| 国产欧美一区二区精品久久久| 99免费在线观看视频| 福利一区和二区| 2021国产精品视频| 色噜噜狠狠狠综合欧洲色8| 中文字幕v亚洲ⅴv天堂| 欧洲天堂在线观看| 精品成人免费观看| 99国产在线播放| 欧亚一区二区三区| 制服.丝袜.亚洲.中文.综合懂色| 亚洲精品视频在线观看免费| 五月婷婷六月香| 久久色视频免费观看| 国产伦精品一区二区三区88av| 精品在线观看视频| youjizzxxxx18| 久久伊人亚洲| 欧美韩国日本在线| 亚洲精品婷婷| 丁香六月激情婷婷| 欧美一区二区三区久久精品茉莉花 | 欧美日韩国产小视频| jizz国产在线观看| 日韩欧美国产激情| 中日韩黄色大片| 亚洲国产va精品久久久不卡综合 | 一本一本大道香蕉久在线精品| 国产一级大片在线观看| 亚洲精品第1页| 五月天婷婷色综合| 亚洲欧美一区二区不卡| 午夜剧场免费在线观看| 中文字幕日韩av资源站| 国产视频精品免费| 中文字幕一区二区视频| 貂蝉被到爽流白浆在线观看| 亚洲国产精品av| 婷婷综合在线视频| 国产精品入口麻豆原神| 日本女人性生活视频| 中文成人av在线| 国产精品69久久久久孕妇欧美| 日本一区二区免费在线观看视频| 超薄肉色丝袜一二三| 中文字幕免费不卡在线| 日本成人精品视频| 亚洲欧美国产77777| 懂色av懂色av粉嫩av| 一区二区三区精品视频在线| 久一视频在线观看| 欧美日韩在线第一页| www.久久视频| 欧美美女一区二区在线观看| 91麻豆成人精品国产免费网站| 欧美一区二区在线不卡| 性一交一乱一伧老太| 亚洲第五色综合网| 欧美孕妇性xxxⅹ精品hd| 亚洲一区二区久久久| 日本在线免费中文字幕| 欧美精品在线免费观看| 99爱在线视频| 国产第一区电影| 国产69精品久久| 91超碰在线免费观看| 国产精品久久久久av蜜臀| 欧美精品亚洲| 99精品电影| 国产白丝袜美女久久久久| 巨乳诱惑日韩免费av| 中文字幕在线观看日| 风间由美一区二区三区在线观看| 一区二区三区少妇| 国产精品国产三级国产a| 久久久久香蕉视频| 一本色道综合亚洲| 99久久精品免费看国产交换| 亚洲国产精品va在线| www日韩tube| 欧美精品久久久久久久| 成人自拍av| 懂色一区二区三区av片| 国产一区二区欧美| av一区二区三区免费观看| 青青草91视频| 欧美激情 亚洲| 中文字幕在线观看不卡| jizz国产免费| 欧美丰满少妇xxxxx高潮对白| 欧美一区二区公司| 久久精品国产成人| 国模冰冰炮一区二区| 爱情岛论坛亚洲入口| 精品国产一区二区三区久久久樱花 | 国产高清一级毛片在线不卡| 欧美激情国产日韩精品一区18| 97欧美成人| 久久人人爽爽人人爽人人片av| 99久久激情| www.欧美日本| www.色综合.com| 精品一区在线观看视频| 欧美午夜理伦三级在线观看| 欧美性猛交 xxxx| 久久国产加勒比精品无码| 秋霞国产精品| 久久福利电影| 亚洲高清电影| 欧美一区二区精美| xxxxxx黄色| 一区二区中文字幕在线| 黄色av一级片| 亚洲精品国偷自产在线99热| 日本电影在线观看| 91九色单男在线观看| 成人影院天天5g天天爽无毒影院| 日韩欧美视频网站| 成人国产精品免费| 九九视频在线免费观看| 在线不卡免费av| 成年人在线观看网站| 欧洲亚洲免费视频| 天堂成人娱乐在线视频免费播放网站| 久久这里只有精品18| 国产一区二区毛片| 日韩高清dvd碟片| 欧美日韩国产电影| 午夜在线播放| 国产一区视频在线播放| 欧美国产一级| 亚洲va综合va国产va中文| 国产精品美女久久久久久 | 欧美日本一区二区| 1024国产在线| 国产在线拍偷自揄拍精品| 欧美精品一二| 天堂网在线免费观看| 日本一区二区三级电影在线观看| 亚洲av无码不卡| 中文字幕国产日韩| 视频欧美精品| 法国空姐在线观看免费| 国产乱色国产精品免费视频| 欧美色图一区二区| 欧美xxxxx牲另类人与| 91探花在线观看| 精品久久久久久乱码天堂| 亚洲自啪免费| 国产精品高清无码在线观看| 欧美亚洲综合一区| 欧洲美女少妇精品| 99re视频在线观看| 欧美福利在线播放| 91国模大尺度私拍在线视频| 国产精品久久久午夜夜伦鲁鲁| www.亚洲天堂| 天堂久久av| 成年人网站免费视频| 国产校园另类小说区| 亚洲中文一区二区三区| 欧美成人网在线| 国产精品一线| 日本熟妇人妻中出| 亚洲欧美日韩精品久久久久| 高清毛片aaaaaaaaa片| 青青草国产精品一区二区| 色777狠狠狠综合伊人| 少妇丰满尤物大尺度写真| 亚洲第一在线综合网站| 成人福利在线| 97人人香蕉| 久久久久久穴| 婷婷在线精品视频| 精品视频在线播放| 亚洲免费一区| 国产精品宾馆在线精品酒店| 日本一区二区高清| 成人毛片在线精品国产| 日本精品视频在线| 中文字幕一区二区精品区| 特大黑人巨人吊xxxx| 欧美久久久久久久久久| 国产在线美女| 中文字幕欧美日韩一区二区三区 | 国产高清自拍一区| 丝袜脚交一区二区| 久久午夜无码鲁丝片| 亚洲天堂男人的天堂| 8x国产一区二区三区精品推荐| 不要播放器的av网站| 亚洲综合精品久久| 137大胆人体在线观看|