关于内核中用到的4层寻址方案的解释

        前面,我大概讲过iblock[15]用于管理某种数据的地址空间的概念,也画过图,但是总有人会绕晕。在这里用更直白的话解释一下。

        背景信息:对于一个传感器,其数据要附加时间信息、空间信息、属性信息等。这些附件的信息可用于检索,目的是实现快速定位满足用户设定条件的数据所在位置。这些数据连同传感器原始数据都存放在一个文件中,那么这些数据要如何组织和存放呢。

        (1)分区存放,先预设一个文件大小,然后进行分区,每个分区放不同的数据。例如,前面放原始数据,后面放时间数据,再后面放空间数据等等。但是这种方案需要预估数据量,一旦预估不准,要么造成空间浪费,要么造成扩展困难。这种方式不现实。

        (2)数据混杂存放,采用更紧凑的方式将数据组织到一起。这种方式便于后续追加写入,便于扩展。但这种方式的管理难度大。因为用户在使用数据时,需要能够在这些混杂的数据中找到所需要的数据。

        不管上述哪种方式,其实都蕴含了一个概念,地址空间。上述两种方式的地址空间划分如下图所示。

 

         我们看图觉得数据只需要按照上面的示意随便存就行了,但是当读的时候怎么办呢?我要的数据在哪里呢?因为上面是没有规律的,所以需要记录各个数据的地址空间。这样将来读取的时候,根据所需要的数据类型,找到对应的地址空间,然后根据该地址空间内的位置,再找到该地址空间和文件逻辑空间的映射关系,就能确定数据在文件内部的偏移量(位置)了。这里的文件逻辑空间,是指把文件当成一个整体,从文件头到文件尾部,整个构成一个线性空间。这个因为存储了多种数据,该地址空间就是多种地址空间的集合,可以称为文件的逻辑地址空间。

        考虑到磁盘按照扇区组织数据,文件系统按照块组织数据,为了提供数据访问效率,文件也是按照块来组织的,也就是说一个物理磁盘上的扇区或者文件系统中的块,只能被某一个文件独占,哪怕该块(扇区)并没有满。由此可知,文件也是按照块组织的。在一个文件内部,文件的地址空间从文件头到文件长度,是按照块划分的,每个块都有一个id,叫文件内部的逻辑块id,这些id是从0开始的连续数字。也可以说该文件的地址空间由这些块组织或者管理。

        有了上述概念,我们可以扩展到各数据地址空间。每个数据都有对应的地址空间,该地址空间是文件地址空间的一个子集。该地址空间也是按照块组织的。文件中的某个块只能存储某一个特定类型的数据,哪怕该类型的数据较少,没有存满该块。对于给定地址空间,想要寻找该该空间内的某一个位置pos,那么只需要找到pos所在的块的首地址,然后加上块内偏移量即可。那么,如何表征块的首地址呢?我们使用块号来表示。

        对于大小为16G的单个地址空间,假设每个块大小为4K,则这16G可以划分成4*1024*1024个块。如何表征这4*1024*1024个块呢,最简单的,弄一个int blockid[4*1024*1024],这样就能一一对应了。数组的每一个元素对应1个块。但是,这种方式带来的缺陷是啥呢?

        在传感器数据管理中,单个数据达到16GB,是一件很轻松的事情。且不说文件大小吧,假设文件最大可能达到16GB,只记录这个文件的块的ID,就需要4M*4=16M空间。对于传感器数据大小分布不均的情况,例如,有的文件达到4TB,需要4G 的地址空间来记录这些块号,有的可能就只有400M,需要400K来存储这些块号。对于这种参差不齐的数据规模,我们不可能为它们实现预留一个统一的空间来存储不同数据对应的块ID,因为开销太大。例如,预留了4GB空间存储这些块ID,结果只用了4M,那就造成严重浪费。另外,当进行文件内容处理时,这些块号要根据需要在内存中缓存。使用4G空间保存块ID,如果都加载到内存中会造成严重浪费。并且,记录每个数据对应的数据块ID,原则上是该数据的元信息,元信息过大,也不利于数据的组织和设计。

        能不能用更少的统一的空间或者模型来存储上述块ID呢?很显然,层次编码是一种常见的方式。上述可以认为是一层线性方式,使用一维数组来存储ID。如果我们使用2层呢?类似下拉菜单那种方式,将这些ID分成多类,第一层表示这些类别,第二层表示该类别下的ID。这种方式其实就相当于空间折叠。

        如上图所示,假设共有9个ID需要表示,如果采用不折叠的方式,就需要一个int blockID[9]来表示地址空间。如果我们采用折叠的方式,则只需要int blockID[3]即可表征所有的9个ID,只不过,这里面把这9个ID存放到数据块中了,假设每个数据块的大小只能表示3个ID,则需要申请3个数据块来存储ID,但是地址空间数据变短了。地址空间数组的元素记录了存储这些ID的块的ID。

        这种算是一级折叠了,假设每块为4K,每个块号使用4个字节,那么一个数据块只能记录1K个ID,那么对于需要4MB来表示地址空间的情形来说,地址空间数组也需要4M/1K=4K空间,这显然也不知何作为元信息存下来。那还嫩更进一步压缩吗?

        很显然,可以。我们可以比葫芦画瓢。将上面的一层折叠改成二层折叠。

          如上图,如果使用二层折叠,则地址空间数组长度仅为1。只不过还需要4个数据块来存储相关的ID。其中3个块(1’\2'\3')存储最原始的9个ID,1个块(1'')存储记录上述3个块的ID。而地址空间数组的元素记录存储上述ID的块的ID(1‘’)。

        同理,我们可以继续折叠,这样地址空间数组的长度就更小了。折叠粒度越大,则地址空间数组长度越小,但是需要的额外数据块来存储这些不同层的块ID也就越多。

        上述的例子中,每一种折叠都只使用了1中折叠。如果我们将多种折叠方式并存呢?就是我们前面讲的iblock[15]四层地址空间管理模型了。

        另外,我还给组内用另外一种方式讲过这个地址空间的折叠问题。就是用图书表示文件,图书的页数表示文件的地址空间。书中有文字、图、表,各有自己的地址空间,也就是页面构成的地址空间。如果我们定义文字、图、表占用纸张的最小单元是页,也就是说每一张图都会占一页,每张表也一样。文字是按照页组织的。图书有文字目录、图目录、表目录。假设一页目录纸只能记录10条记录,如果我们的图书中文字较多,页数较多,那么文字的目录就会很长,需要占用很多页。我们是无法提前预估是有多少页保留下来给文字目录的。假设我们是编写边编辑目录,每写一页就增加一条目录。那事先预留的方式肯定够呛,扩展性不足。那怎么办呢?

        我们会采用边写边插入的方式,按需生成目录条目,插在正文中,也是以页为单位,该页上面只有目录条目。如果还是这种组织方式,那么存储目录所需要的页数是不会变的,只是原来预留方式下,目录都在图书前面,而现在目录可能穿插在正文中,但所需要的页面并没有减少。那么如果图书最开始的目录只能有一页文字目录、一页图目录和一页表目录,我们该如何充分利用地址空间呢?

        你可以把图书最前面的那一个目录页的第10条作为指针,记录下一个对应目录页的地址。这样就将同类型的目录页串起来了。这种方式当然是可行的,但是对于10条之外的目录项,我们都要从第一个目录页开始,通过链表的方式逐个读取目录页,然后找我们想要的目录项,这种效率肯定高不了。那么能不能在第一页的目录页就把全书的目录信息都概括进去呢?

        可以,我们使用目录折叠方式,在目录首页呈现一个全书概况,在图中夹杂的目录页呈现细节,具体解释和上面差不多,不再多讲。

        

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值