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

MD中bitmap源代码分析--数据结构的更多相关文章

  1. MD中bitmap源代码分析--入题概述

    在MD模块中,各级raid都使用的一份bitmap的源码,也就是说共用一种bitmap的流程,下面以raid1的使用为例来分析bitmap的工作原理. 在使用raid1磁盘阵列的时候,对于数据的可靠性 ...

  2. MD中bitmap源代码分析--SYNC IO和RAID5的补充

    最近在做bwraid的R6的设计工作,需要调研一下bitmap下刷磁盘的IO属性(是否为SYNC IO),还有raid5中bitmap的存储和工作方式. 1.bitmap刷磁盘是否为 SYNC IO? ...

  3. MD中bitmap源代码分析--清除流程

    bitmap的清零是由bitmap_daemon_work()来实现的.Raid1守护进程定期执行时调用md_check_recovery,然后md_check_recovery会调用bitmap_d ...

  4. MD中bitmap源代码分析--状态机实例

    1. page_attrs的状态转换关系 之前说过,bitmap的优化核心是:bitmap设置后批量写入:bitmap延时清除.写bit用bitmap_statrwrite() + bitmap_un ...

  5. MD中bitmap源代码分析--设置流程

    1. 同步/异步刷磁盘 Bitmap文件写磁盘分同步和异步两种: 1) 同步置位:当盘阵有写请求时,对应的bitmap文件相应bit被置位,bitmap内存页被设置了DIRTY标志.而在下发写请求给磁 ...

  6. Memcached源代码分析 - Memcached源代码分析之消息回应(3)

    文章列表: <Memcached源代码分析 - Memcached源代码分析之基于Libevent的网络模型(1)> <Memcached源代码分析 - Memcached源代码分析 ...

  7. Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6633311 在上一篇文章中,我 们分析了And ...

  8. Java中arraylist和linkedlist源代码分析与性能比較

    Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arra ...

  9. FreeBSD 5.0中强制访问控制机制的使用与源代码分析【转】

    本文主要讲述FreeBSD 5.0操作系统中新增的重要安全机制,即强制访问控制机制(MAC)的使用与源代码分析,主要包括强制访问控制框架及多级安全(MLS)策略两部分内容.这一部分讲述要将MAC框架与 ...

随机推荐

  1. Java基础知识强化71:正则表达式之基本规则 和 常用正则表达式

    1. 基本规则: A:字符 x 字符 x.举例:'a'表示字符a \\ 反斜线字符. \n 新行(换行)符 ('\u000A') \r 回车符 ('\u000D') B:字符类 [abc] a.b 或 ...

  2. LA 6449 IQ Test

    [题目] 给出一个长度为n的数组(8<n<12),告诉你规律  (1<=d<=3)要求d尽量小 现在求第n+1项 [题解] 水题 不知道怎么求a1~ad? 用克拉默法则 [代码 ...

  3. vs2012加载EntityFrameWork框架,连接Oracel

    近日公司用到.net MVC框架做接口,需连接到Oracel数据库,从网上查阅了一些资料,当然,从咱们博客园获益匪浅.然后结合自己所做,把使用过程中遇到的一些问题,及如何解决的整理如下,方便查阅,也有 ...

  4. awk命令简单学习

    请执行命令取出linux中eth0的IP地址(请用cut,有能力者也可分别用awk,sed命令答). 解答: 说明:此题解答方法已经给大家讲解了不下15种,还可以有很多,在这里给大家着重讲下awk的技 ...

  5. IOS创建开源库步骤,提交cocoa pods官网,别人可以使用

    1.打开终端进入某个目录执行  pod lib create BMBlinkButton,按命令步骤执行. 2.目录结构 3.修改BMBlinkButton.podspec文件 4.进入Example ...

  6. iOS 改变UITextField中光标颜色

    第一种: [[UITextField appearance] setTintColor:[UIColor blackColor]]; 这个方法会影响整个app的所有UITextFiled... 第二种 ...

  7. UITableView出现卡顿如何处理

    tableView的beginUpdate和endUpdate要比reloadData和reloadRowsAtIndexPaths好,因为beginUpdate和endUpdate会执行一个动画bl ...

  8. Swift - 37 - 值类型和引用类型的简单理解

    //: Playground - noun: a place where people can play import UIKit // 值类型:指的是当一个变量赋值给另外一个变量的时候, 是copy ...

  9. Interview Algorithm

    约瑟夫环: #include <stdio.h> #include <stdlib.h> #include <string.h> int find(int *arr ...

  10. 详解boost库中的Message Queue .

    Message Queue(后文简写成MQ或消息队列)是boost库中用来封装进程间通信的一种实现,同一台机器上的进程或线程可以通过消息队列来进行通迅.消息队列中的消息由优先级.消息长度.消息数据三部 ...