MD中bitmap源代碼分析--數據結構


  本篇分析bitmap的數據結構的設計,並基於此分析bitmap的工作機制。

  為了后面更清楚的理解,先有個總體印象,給出整體的結構圖:

 

  在下面的描述中涉及到的內容可以對照到上圖中相應部分,便於理解。

  首先,我們從宏觀的角度來分析整體結構。bitmap file存在於磁盤,內部存放着很多個bit,每個bit對應於磁盤數據中的一個chunk。在內存空間中也存在一個區域存放bitmap file緩存,與磁盤bitmap file的每個bit一一對應。內存空間中還存在一個區域存放filemap_attr,用來管理bitmap file緩存中每個page的頁屬性。內存空間中還存在一個區域存放和管理*bmc,用來管理對應bitmap file中的bit是否置位和未完成的最大請求數。而這些內存區域的操作都由bitmap這個大結構體關聯起來。如下圖所示。

 

  1. bitmap的結構體有比較多的字段,這里關注幾個重要的字段。

    struct bitmap {

      struct bitmap_page *bp; /*指向內存bitmap頁的結構*/

      ……

      unsigned long chunks; /*陣列總的chunk數*/

      ……

      struct file *file; /*bitmap文件*/

      ……

      struct page **filemap; /*bitmap文件的緩存頁*/

      unsigned long *filemap_attr; /*bitmap文件緩存頁的屬性*/

      unsigned long file_pages; /*  1、初始化時當做page號累加,

                     2、初始化完成之后,為bitmap file中的page數

                    */

       ……

    };

   這里filemap是指向一系列page結構緩存頁的指針構成的數組,所以是page**類型。其在內存中的結構和與bitmap file緩存的關系如下圖所示。

 

  2. 其中struct bitmap_page結構如下:

    struct bitmap_page {

      char *map; /*指向實際分配的內存頁*/

      unsigned int hijacked:1; /* 表示是否被劫持。

                    置1的時候說明,內存空間不夠的時候使用,

                    這時直接將map指針作為兩個*bmc

                   */

      unsigned int count:31; /*該頁上有多少臟的chunk */

    };

     bp的整體結構如下如所示:

 

  在正常情況下(內存充足),bitmap的bp字段指向一片內存區域,該內存區域就是逐一存放的bitmap_page結構體,也就是結構體數組。而每個這樣一個結構體中存在一個map指針,在需要的時候就會在內存中開辟一個page的空間,用來存放逐一存放*bmc。這里map指針指向的page是動態分配的,在需要的時候才會分配page並設置使用相應的*bmc。

  對於bp指針指向的bitmap_page結構,內部分為3個字段。其中的hijacked字段大多數情況下都是置為0的,這也就是內存空間足夠分配page的正常情況。這種情況下一個*bmc管理1個bitmap file緩存中的1個bit,一個*map指針管理一個page,而一個page可以存放2048個*bmc(一個*bmc為16位,后面會介紹到),也就是一個map指針管理2048個bitmap file緩存中的bit,count用來作為該map指針管理下的這2048個*bmc對應有多少臟的chunk計數。如下圖所示。

 

  hijacked字段置為1的情況十分少見,只有在內存空間不夠分配page的時候才會將hijacked字段置為1。在這種情況內存不足,分配不了page空間,那么就退而求其次,將*bmc的管理粒度變大,具體方法如下。bitmap_page結構中的3個字段, map指針本來是要指向page的,但是page沒有空間分配,所以就直接將map指針另作它用。指針的大小不論是32位還是64位,其大小至少能容納下32位,即2個*bmc。那么就直接將map指針的前32位看作是2個*bmc,一個*bmc管理1024個bitmap file緩存中的bit,這樣兩個*bmc管理2048個bit,正好與正常情況下一個bitmap_page結構管理的bit數目一致,只是管理bit的粒度變大了;而count字段仍然來統計這2048個bit對應有多少臟的chunk的計數。如下圖所示。

 

 

  3. 實際動態分配的每個內存頁,每16bit管理對應bitmap文件的一個bit,一個bit對應一個chunk(數據塊)。這16bit在代碼中記作*bmc,它的作用如下:

 

    NEEDED_MASK——表示該bit對應的chunk是否需要同步;

    RESYNC_MASK——表示該bit對應的chunk是否正在同步;

  NEEDED_MASK和RESYNC_MASK標志是不會同時存在的,盤陣需要同步時,會先設置NEEDED_MASK標志,當下次檢查到有NEEDED_MASK標志時,表示需要同步,此時清除該標志,設置RESYNC_MASK標志,進行同步。如果同步出錯,則清除RESYNC_MASK標志,設置NEEDED_MASK標志。內存bitmap的另一個作用是在精准恢復或者同步時判斷一個bitmap-chunk是否需要恢復或者同步,即NEEDED_MASK和RESYNC_MASK的作用。

  低14位是counter,用來統計對應的chunk尚未完成的寫請求的計數。真正的計數值是從2開始累加,表示有寫操作(比如有2個未完成寫操作,則值為4)。counter的值為0、1、2均為沒有寫操作,是特殊狀態:

    *bmc=0——該bit位需要下刷;

    *bmc=1——該bit位需要清零;

    *bmc=2——該bit對應的chunk上的寫操作全部完成,表示該bit可以被清除並下刷。從2開始計數。

  *bmc與bitmap file緩存的對應關系如下如所示:

 

  4. Bp數組中的map字段是一個指針,指向一個page頁,該page頁中順序存放*bmc,一個page可以存放2048*bmc。一個*bmc對應bitmap file中的一個bit,也就是對應數據中的一個chunk也就是說bp數組的第二項的map指針指向的page頁的第一個*bmc,是整體的第2049個*bmc(下標為0稱為第1個)。

  *bmc實際作用是控制bitmap的置位與復位,並且也控制一個chunk上的請求不能超過最大值(14bit表示的最大整數),達到最大值的時候會進行IO schedule。

  當內存空間不足夠分配*bmc的時候,那么hijacked置位,將map指針本身當做兩個*bmc,此時一個*bmc就不再只是對應bitmap file中的一個bit,而是半個page的bit,兩個*bmc可以管理正好一個page的bit。也就是說如果空間不夠的話,*bmc的管理粒度就增大了。

  數據chunk、bp、*map page和attr都是順序排列的,可以使用順序尋找,一一對應的方法將他們關聯起來。

 

  5. filemap_attr表示bitmap文件緩存頁的屬性,使用4bit來表示:

    BITMAP_PAGE_DIRTY——表示內存bitmap有bit被置位,但是bitmap file對應的位沒有被置位,因此page需要同步刷到磁盤,寫磁盤完成才能繼續

    BITMAP_PAGE_CLEAN——這是一個過渡狀態,表示內存bitmap有可以清除的bit,則需要清除該bit,然后過渡到BITMAP_PAGE_NEEDWRITE狀態;

    BITMAP_PAGE_NEEDWRITE——表示內存bitmap有bit被清除,但是bitmap file對應的位沒有被清除,因此page需要刷到磁盤,但是異步進行的,因為即使寫失敗,最多帶來額外的同步,不帶來數據的危害

  其在內存中的結構和與bitmap file緩存的關系如下如所示:

 

  6. 分析bitmap整體結構關系:

    bitmap在內存中相關結構的關系如下如所示:

 

    Bitmap對於內存和磁盤的交互關系如下如所示:

 

    為了便於理解,下面給出一個計算實例,以3個page的bit為例。計算過程在紅字中標出,如下圖所示:

 

    將上述結構串聯起來,得到一個bitmap的整體結構,如下圖所示:

 

    上圖中,實線代表的是對象關系,虛線代表的是控制關系。

 

  重新回顧一次“概要”一章中的故事。首先當沒有bitmap的時候,就只有磁盤中存在有Data而沒有其他結構,如圖中右下角;當引入bitmap之后,則在磁盤中還存在了一種“數據”叫做bitmap file,bitmap file的一個bit對應盤陣的一個chunk,在盤陣數據寫入前,設置該chunk對應的bit,盤陣寫入完成,則清除該bit。要進行同步時,參照bitmap,只有置位的bit對應的chunk才需要進行同步,這樣縮短了同步的時間,提高了效率。

  bitmap原理很明了,按照這個原理直接進行實施也是可以的,但直接這樣實施的話,由於一次數據塊的寫入多了兩次磁盤訪問(bitmap的設置和清除),寫入效率會受到較大影響,所以還需要考慮一些優化。優化主要是兩方面的:

    1、bitmap設置后批量寫入;

    2、bitmap延時清除。

  這兩方面的優化,需要在內存中構建和磁盤bitmap文件對應的數據bitmap file緩存,bitmap操作首先在緩存中進行,必要時才進行真正的磁盤操作。內存中bitmap file緩存與磁盤上的bitmap file每個bit一一對應,所以內存bitmap file緩存中的一個bit也與對應的磁盤bitmap file中的bit一樣對應於Data中的一個chunk。對於bitmap file緩存自身的每一個page都有filemap_attr來管理頁狀態,並且bitmap file緩存中的每一個bit在內存中都有16個bit的結構*bmc來進行管理。

  bitmap結構體下,**filemap指向bitmap file緩存的一個page,filemap_attr字段管理一個bitmap file緩存page的頁狀態,bp->map指向一個page(需要時才分配page空間),其中存放的都是*bmc,一個*bmc有16位,每個*bmc用來管理對應的bitmap file緩存的1個bit,bitmap file緩存與磁盤上的bitmap file互相對應,其中每個bit對應了Data中的相應chunk的數據寫入狀態,就將整個bitmap框架連接了起來。

 

轉載請注明出處:http://www.cnblogs.com/fangpei


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM