本篇分析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