InnoDB源碼分析--緩衝池(二)

来源:http://www.cnblogs.com/wingsless/archive/2016/06/12/5578727.html
-Advertisement-
Play Games

轉載請附原文鏈接:http://www.cnblogs.com/wingsless/p/5578727.html 上一篇中我簡單的分析了一下InnoDB緩衝池LRU演算法的相關源碼,其實說不上是分析,應該是自己的筆記,不過我還是發揚大言不慚的精神寫成分析好了。在此之後,我繼續閱讀了Buf0rea.c文 ...


     轉載請附原文鏈接:http://www.cnblogs.com/wingsless/p/5578727.html

    上一篇中我簡單的分析了一下InnoDB緩衝池LRU演算法的相關源碼,其實說不上是分析,應該是自己的筆記,不過我還是發揚大言不慚的精神寫成分析好了。在此之後,我繼續閱讀了Buf0rea.c文件,因為這裡寫的就是如何將block讀取到記憶體中的函數。

    這個文件里很顯眼的有這樣一個函數:buf_read_page,這是一個高層的函數,它的作用就是:reads a page asynchronously from a file to the buffer buf_pool if it is not already there。採用非同步的方式將文件中的頁讀入buf_pool。大體上看一眼這個函數,發現它主要搞了以下幾個工作:

    1 隨機預讀(buf_read_ahead_random)。隨機預讀是一個可以提高效率的策略,它的主要思想是:給定的space和offset確定的那頁,可以計算出一個範圍,如果這個範圍內的頁(pages)有一部分已經被訪問(閾值:BUF_READ_AHEAD_RANDOM_THRESHOLD),那麼這個範圍內的頁(pages)就會被預讀。看一下函數內是怎麼寫的:

//確定一個邊界,邊界內的頁,都要進行條件判斷
low = (offset / BUF_READ_AHEAD_RANDOM_AREA) * BUF_READ_AHEAD_RANDOM_AREA; high = (offset / BUF_READ_AHEAD_RANDOM_AREA + 1) * BUF_READ_AHEAD_RANDOM_AREA; if (high > fil_space_get_size(space)) { high = fil_space_get_size(space); } 省略部分...
//對邊界內的頁進行條件判斷
for (i = low; i < high; i++) { block = buf_page_hash_get(space, i); if ((block) && (block->LRU_position > LRU_recent_limit) && block->accessed) { recent_blocks++; } } mutex_exit(&(buf_pool->mutex)); if (recent_blocks < BUF_READ_AHEAD_RANDOM_THRESHOLD) { /* Do nothing */ return(0); } 省略部分...
//如果之前的判斷都通過,則函數可以進行下麵的步驟
//邊界範圍內的每一個頁都會被預讀:(buf_read_page_low),預讀採用非同步的方式
for (i = low; i < high; i++) { /* It is only sensible to do read-ahead in the non-sync aio mode: hence FALSE as the first parameter */ if (!ibuf_bitmap_page(i)) { count += buf_read_page_low( &err, FALSE, ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, space, tablespace_version, i); if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Warning: in random" " readahead trying to access\n" "InnoDB: tablespace %lu page %lu,\n" "InnoDB: but the tablespace does not" " exist or is just being dropped.\n", (ulong) space, (ulong) i); } } }

     滿足條件的頁就會被預讀,註意預讀採用非同步的方式,同時,(space,offset)指定的頁,也會被預讀。這裡是一個我有點搞不明白的地方,這個頁既然被非同步預讀了,後面還會在同步的讀取一次,且聽後話。

     2 物理讀取。預讀結束之後,buf_read_page函數就會調度buf_read_page_low函數,進行數據的讀取,註意這個函數剛纔預讀的時候也使用過,但是這次採用同步的方式,註釋寫的很明白:“ We do the i/o in the synchronous aio mode to save thread”。這個函數還會在給block->frame加x-lock鎖,這個操作會在函數調度下一級函數buf_page_init_for_read的時候進行,代碼:rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ)。而buf_page_init_for_read函數的主要作用就是從LRU里分配一個buf_block_t*,並對這個buf_block_t*加x-lock鎖。我主要看到了這幾行:

//分配一個buffer block
block = buf_block_alloc();
//向buffer pool中初始化一個page buf_page_init(space, offset, block);
//將block插入LRU鏈表中,只能插入old鏈表 buf_LRU_add_block(block, TRUE);
/* TRUE == to old blocks */ rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);

    註意,buf_read_page_low函數中最後有這樣一段:

if (sync) {
        /* The i/o is already completed when we arrive from
        fil_read */
        buf_page_io_complete(block);
    }

     如果是同步方式,那麼就用buf_page_io_complete函數釋放所有的x-lock:rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ);

     3 物理讀取結束之後,會調度buf_flush_free_margin函數,在需要的情況下,flush掉LRU鏈表的尾部。

     

     總結一下上面的步驟,發現這是地地道道的物理讀取,即從磁碟中將數據讀取到記憶體中。在《MySQL內核--InnoDB存儲引擎》一書的12章里還介紹了一種讀取方式叫做邏輯讀取,現在分析如下。

     從書中的描述里看,我覺得這個叫做邏輯讀取有點不好理解。個人覺得這個邏輯讀取其實就是一個流程:

     

      基於我的理解畫的,可能有疏漏的地方。這裡就需要看這個函數:buf_page_get_gen,它的註釋也寫得很明白:This is the general function used to get access to a database page。提供了一個訪問資料庫頁的通用方法。

     這個函數有個很有意思的地方就是它的入參里有很多的mode,這就給該函數帶來了許多種可能的返回。我無心看這些,但是有一個地方卻很吸引我,就是一個goto。學C的時候老師說,goto是C語言歷史上臭名昭著的一個關鍵字,大家初學,千萬別用。但是又有持不同意見的人認為善用goto能帶來意想不到的效果,我相信MySQL的作者們goto用的非常好。

     函數中有一個loop標記,也就是說函數是迴圈著讀取block的,直到滿足一些條件。首先會從緩衝池裡尋找:block = buf_page_hash_get(space, offset),沒有的話就會使用這個函數:buf_read_page(space, offset)將block讀入,然後goto到開始的地方,將block置為NULL,重新開始,這次就能從緩衝池裡找到block了。下麵的代碼是很多的判斷,不過這裡很顯眼:

mutex_exit(&buf_pool->mutex);

    /* Check if this is the first access to the page*/    accessed = block->accessed;

    block->accessed = TRUE;

    mutex_exit(&block->mutex);

    buf_block_make_young(block);

省略部分...
if (!accessed) {
/* In the case of a first access, try to apply linear
read-ahead */

buf_read_ahead_linear(space, offset);
}

 

    這裡判斷了block是不是第一次被訪問,但是很奇怪,這個block立刻就被make young了,這和我以前的認知倒是不太一樣了,不過這篇淘寶丁奇的博文(https://yq.aliyun.com/articles/8827)里寫到了這一點,可以參考一下,經過我的分析發現,make young也不是那麼笨的,它要判斷這個block是不是需要被make young(if (buf_block_peek_if_too_old(block)))。如果是第一次被訪問,就會觸發線性預讀函數的調用。

    終於說到了線性預讀。留著明天寫吧。

    看代碼果然過癮啊。

    


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在SQL SERVER中列許可權(Column Permissions)其實真沒有什麼好說的,但是好多人對這個都不甚瞭解,已經被人問了幾次了,所以還是在這裡介紹一下,很多人都會問,我能否單獨對錶的某列授權給某個用戶? 答案是可以,我們可以對錶中的列授予SELECT、UPDATE許可權,我們結合下麵的簡單... ...
  • 通常在我寫EXISTS語句時,我會寫成IF EXISTS(SELECT TOP(1) 1 FROM XXX),也沒細細考究過為什麼要這麼寫,只是隱約認為這樣寫沒有啥問題,那今天就深究下吧! 首先準備測試測試數據 其中需要註意下索引IDX_ID, 雖然ID已經是主鍵索引,但仍創建一個非聚集索引以供後續 ...
  • 由於從各光伏電站採集的數據量較大,必須解決海量數據的查詢、分析的問題。目前主要考慮兩種方式:1. Hadoop大數據技術;2. Oracle(數據倉庫)+BI; 本文僅介紹hadoop的技術要應用特征。 Hadoop 基本介紹 hadoop是一個平臺,是一個適合大數據的分散式存儲和計算的平臺。什麼是 ...
  • 控制文件是Oracle資料庫中一種非常重要的文件。 在Oracle資料庫中主要包括:數據文件、控制文件和重做日誌文件。在數據文件中存儲資料庫中的數據,包括各種資料庫對象及其數據。在重做日誌文件中存放用戶執行DML及DDL命令的記錄。 在控制文件中存放資料庫的結構信息。具體來說,在控制文件中包含以下重 ...
  • MicrosoftSQL Server 提供了三種複製類型。 每種複製類型都適合於不同應用程式的要求。 根據應用程式需要,可以在拓撲中使用一種或多種複製類型: 快照複製 事務複製 合併複製 為了幫助您選擇適當的複製類型,此主題提供了有關下列內容的信息: 複製方案 本部分簡要描述了複製的多種常用情況, ...
  • 1、 查詢Student表中的所有記錄的Sname、Ssex和Class列。 2. 查詢Student表的所有記錄。 3.查詢Score表中成績在60到80之間的所有記錄 4.查詢Score表中成績為85,86或88的記錄。 5.查詢Student表中“95031”班或性別為“女”的同學記錄。 6. ...
  • 在使用YourSQLDba做資料庫備份、維護時,像其它軟體一樣,版本升級是不可避免的。因為YourSQLDba一直在不停更新版本、擴展功能。下麵介紹一下升級YourSQLDba時的具體步驟和一些註意事項。下麵案例,YourSQLDba原版本為YourSQLDba version: 5.0.2 201... ...
  • 一、表訪問方式 CBO基礎概念中有講到,訪問表的方式有兩種:全表掃描和ROWID掃描。 全表掃描的執行計劃:TABLE ACCESS FULL ROWID掃描對應執行計劃:TABLE ACCESS BY USER ROWID 或 TABLE ACCESS BY INDEX ROWID 通過例子說明 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...