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頁的結構*/spa

      ……設計

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

      ……指針

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

      ……

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

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

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

                     二、初始化完成以後,爲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、一、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的設置和清除),寫入效率會受到較大影響,因此還須要考慮一些優化。優化主要是兩方面的:

    一、bitmap設置後批量寫入;

    二、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

相關文章
相關標籤/搜索