TFS数据服务器的block是在DS第一次启动前格式化的,所有block的空间是预先分配好的,而物理块对应的index文件,则是block被分配使用时创建的。Index文件的大小是根据block中文件数目增加而增长的,为了提高性能,将整个index文件都mmap到内存直接访问。

在初次mmap index文件时,会计算block中预期的文件数,计算出index文件的理论大小index_size,然后调用ftruncate将index文件的大小改为index_size(保证后面的mmap能成功),然后将0~index_size的内容映射到内存。

由于ftruncate只会改变文件大小,而不会实际分配磁盘空间(man ftruncate),所以index文件的存储空间都是在index文件写的时候动态分配的,当向mmap某个未分配空间的地址写数据时,如果磁盘满,则空间分配会失败,接下来对该地址的写操作将会core掉。下面通过一个实例模拟一下出core的过程。

  1. 创建一个1G的文件的普通文件
    clip_image002

  2. 在该文件上创建文件系统,并以loop形式挂载

    sudo mkfs.ext4 loop_device
    sudo mount –t ext4 –o loop loop_device /mnt/loop

    clip_image004

  3. 在挂载目录下,创建一个文件testfile,并调用ftruncate将其大小改为2G

    clip_image006

  4. 再向挂载目录中下写入一个1g的文件realfile,由于文件系统空间总共只有983M,故dd时提示磁盘空间不足,只能成功写入983M;可以看出,ftruncate并没有实际的分配磁盘空间。

    clip_image008

  5. 最后mmap映射testfile的前面一部分文件数据(前10M),并直接向映射的地址写数据。

    clip_image010

运行以上程序,会core掉,Program terminated with signal 7, Bus error. 原因是testfile只是个空文件,当需要为其分配磁盘空间时,磁盘已经满了,接下来对testfile映射的地址的访问就会出core,但为什么是SIGBUS,而不是SIGSEGV,我也不得而知,求高人指点。

Block对应的Index的空间是根据平均文件大小的配置项计算出理论值大小,并在格式化前会为index预留对应的存储空间,之后创建的index都只有这部分存储空间,造成index无法分配到空间(磁盘满)主要有以下几个原因:

  1. DataServer挂载大小配置高于文件系统实际可用空间,这时预留给index的空间比实际计算出来的小,这个问题可以通过在代码上加以检查来避免。
  2. Block中大量小文件,index条数量严重偏离预期,该问题目前没有想到好的办法解决。
  3. 大量删除block时产生的延时删文件没有正常被回收,占用大量空间,导致正常的index文件分配不到空间,可通过对延时删机制进行改进来避免。

ref:
2013-04-19 14:13
blog.yunnotes.net


ccj 于 2017-12-20 21:42 修改
0 回复
需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。