首页 > 编程知识 正文

ffs是什么,运行hadoop伪分布式实例

时间:2023-05-06 03:05:47 阅读:153713 作者:2859

F2FS源代码分析系列文章主目录1、文件系统布局和元数据结构2、 保存和读写文件数据F2FS如何组织文件数据一般文件写入过程一般文件读取过程目录文件读取过程(未完成)目录文件写入过程(未完成) 3、创建和删除文件和目录数据恢复机制6、关键数据结构或函数分析文件数据的存储和物理地址映射文件数据的组织方式一般设计为inode-data模式。 这意味着每个文件都有一个inode,该inode记录data的组织关系。 这种关系称为文件结构。 例如,如果用户需要访问a文件的第1000个字节,系统会首先根据a文件的路径找到a的inode,然后从inode中找到第1000个字节的物理地址,然后从磁盘中读取。 那么F2FS的文件结构怎么样了呢?

如上图所示,F2FS的一个inode包含两个主要部分:元数据部分和块地址部分。 重点观察块地址部分,分析inode如何索引块。 图中的块地址部分包含direct pointers、single-indirect、double-indirect和triple-indirect。 各自的意思如下

direct pointer:inode内直接指向数据块(图右上方的数据)的地址阵列(即inode-data模式)。

single-indirect pointer:inode记录两个single-indirect pointer (图右上方的Direct node ),每个single-indirect pointer记录多个数据块的地址、地址

inode-direct_node-data模式inode记录了两个双精度节点(图右上方的双精度节点),每个双精度节点记录了许多单精度节点

double-indirect:inode中记录了三重索引节点(图右上方的索引节点), 每个三重索引点都记录了很多双索引。每个双索引点记录了很多单索引点,最后每个单索引点都记录了很多单索引点即inode-indirect_node-direct_node-data模式

因此,可以看出F2FS的inode结构取indirect_node,首先在inode内部查找物理地址,如果找不到就去direct_node,层次变深了。

f2fs_node的结构和作用根据上述分析,可以将寻址信息间接存储在可能包含非节点的大型文件中。 单指令点记录数据块的地址,双指令点记录单指令点的地址,三指令点记录

I节点对应于f2fs_I节点结构,其中多个直接点指向数据块的物理地址。

single-indirect pointer对应于direct_node结构,且多个direct pointer指示物理地址;

double-indirect pointer对应于indirect_node结构,并且包括到direct_node的多个地址;

triple-indirect pointer也对应于indirect_node结构,并且包含indirect_node的多个地址

然后,逐一分析F2FS各node的具体数据结构。

为了便于区分和管理F2FS的节点,基本节点结构使用f2fs_inode、direct_node和indirect_node相同的数据结构f2fs_node进行描述,通过union的方式将f2fs_node

struct f2f s _ node { union } struct f2f s _ inodei; struct direct_node dn; struct indirect_node in

;};struct node_footer footer; // footer用于记录node的类型} __packed;struct node_footer {__le32 nid;/* node id */__le32 ino;/* inode nunmber */__le32 flag;/* include cold/fsync/dentry marks and offset */__le64 cp_ver;/* checkpoint version */__le32 next_blkaddr;/* next node page block address */} __packed;

其中起到区分是哪一种node的关键数据结构是node_footer。如果node_footer的nid和ino相等,则表示这是一个f2fs_inode结构,如果不相等,则表示这是一个direct_node或者indirect_node。

f2fs_inode结构

我们先看f2fs_inode的结构,省略其他元数据的信息,重点关注文件如何索引的,结构如下:

struct f2fs_inode {...__le32 i_addr[DEF_ADDRS_PER_INODE]; // DEF_ADDRS_PER_INODE=923__le32 i_nid[DEF_NIDS_PER_INODE];// DEF_NIDS_PER_INODE=5...} __packed;

i_addr数组就是前面提及的direct pointer,数组的下标是文件的逻辑位置,数组的值就是flash设备的物理地址。例如文件的第一个页就对应i_addr[0],第二个页就对应i_addr[1],而i_addr[0]和i_addr[1]所记录的物理地址,就是文件第一个页(page)和第二个页的数据的物理地址,系统可以将两个物理地址提交到flash设备,将数据读取出来。

我们可以发现i_addr的数组长度只有923,即一个f2fs_inode只能直接索引到923个页/块的地址(约3.6MB),对于大于3.6MB的文件,就需要使用间接寻址。f2fs_inode的i_nid数组就是为了间接寻址而设计,i_nid数组是一个长度为5的数组,可以记录5个node的地址。其中

i_nid[0]和i_nid[1]记录的是direct_node的地址,即对应前述的single-indirect pointer。

i_nid[2]和i_nid[3]记录的是indirect_node的地址,这两个indirect_node记录的是direct_node的地址,即对应前述的double-indirect pointer。

i_nid[4]记录的是indirect_node的地址,但是这个indirect_node记录的是indirect_node的地址,即前述的triple-indirect pointer。

direct_node和indirect_node结构

direct_inode以及indirect_inode的结构如下所示,direct_node记录的是数据块的地址,indirect_inode记录的是node的id,系统可以通过nid找到对应的node的地址。

struct direct_node {__le32 addr[ADDRS_PER_BLOCK]; // ADDRS_PER_BLOCK=1018} __packed;struct indirect_node {__le32 nid[NIDS_PER_BLOCK]; // NIDS_PER_BLOCK=1018} __packed; Wandering Tree问题

在第一章的第一节提到,F2FS的设计是为了解决wandering tree的问题,那么现在的设计是如何解决这个问题的呢。假设一个文件发生更改,修改了direct_node里面的某一个block的数据,根据LFS的异地更新特性,我们需要给更改后的数据一个新的block。传统的LFS需要将这个新的block的地址一层层网上传递,直到inode结构。而F2FS的设计是只需要将direct_node对应位置的addr的值更新为新block的地址,从而没必要往上传递,因此解决了wandering tree的问题。

普通文件数据的保存

从上节描述可以知道,一个文件由一个f2fs_inode和多个direct_inode或者indirect_inode所组成。当系统创建一个文件的时候,它会首先创建一个f2fs_inode写入到flash设备,然后用户往该文件写入第一个page的时候,会将数据写入到main area的一个block中,然后将该block的物理地址赋值到f2fs_inode->i_addr[0]中,这样就完成了Node-Data的管理关系。随着对同一文件写入的数据的增多,会逐渐使用到其他类型的node去保存文件的数据。

经过上面的分析,我们可以计算F2FS单个文件的最大尺寸:

f2fs_inode 直接保存了923个block的数据的物理地址f2fs_inode->i_nid[0~1] 保存了两个 direct_node 的地址,这里可以保存 2 x 1018个block的数据f2fs_inode->i_nid[2~3] 保存了两个indirect_node 的地址,这两个其中2个indirect_node保存的是 direct_node 的nid,因此可以保存 2 x 1018 x 1018个block的数据;f2fs_inode->i_nid[4] 保存了一个indirect_node 的地址,这个indirect_node保存的是 indirect_node 的nid,因此可以保存 1018 x 1018 x 1018个页的数据

可以得到如下计算公式:
4KB x (923 + 2 x 1018 + 2 x 1018 x 1018 + 1 x 1018 x 1018 x 1018) = 3.93TB
因此F2FS单个文件最多了保存3.93TB数据。

内联文件数据的保存

从上节可以知道,文件的实际数据是保存在f2fs_inode->i_addr对应的物理块当中,因此即使一个很小的文件,如1个字节的小文件,也需要一个node和data block才能实现正常的保存和读写,也就是需要8KB的磁盘空间去保存一个尺寸为1字节的小文件。而且f2fs_inode->i_addr[923]里面除了f2fs_inode->i_addr[0]保存了一个物理地址,其余的922个i_addr都被闲置,造成了空间的浪费。

因此F2FS为了减少空间的使用量,使用内联(inline)文件减少这些空间的浪费。它的核心思想是当文件足够小的时候,使用f2fs_inode->i_addr数组直接保存数据本身,而不单独写入一个block中,再进行寻址。因此,如上面的例子,只有1个字节大小的文件,只需要一个f2fs_inode结构,即4KB,就可以同时将node信息和data信息同时保存,减少了一半的空间使用量。

根据上述定义,可以计算得到多大的文件可以使用内联的方式进行保存,f2fs_inode有尺寸为923的用于保存数据物理地址的数组i_addr,它的数据类型是__le32,即4个字节。保留一个数组成员另做它用,因此内联文件最大尺寸为: 922 * 4 = 3688字节。

文件读写与物理地址的映射的例子

Linux的文件是通过page进行组织起来的,默认page的size是4KB,使用index作为编号。

一个小文件访问例子

例如一个size=10KB的文件,需要3个page去保存数据,这3个page的编号是0,1,2。当用户访问这个文件的第2~6kb的数据的时候,系统就会计算出数据保存在page index = 0和1的page中,然后根据文件的路径找到对应的f2fs_inode结构,page index = 0和1即对应f2fs_inode的i_addr[0]和i_addr[1]。系统进而从这两个i_addr读取物理地址,提交到flash设备将数据读取出来。

一个大文件访问例子

假设用户需要读取文件第4000个页(page index = 3999)的数据,
第一步: 那么首先系统会根据文件路径找到对应的f2fs_inode结构
第二步: 由于4000 >(923 + 1018 + 1018),f2fs_inode->i_addr和f2fs_inode->nid[0]和nid[1]都无法满足需求,因此系统根据f2fs_inode->nid[2]找到对应的 indirect_node的地址
第三步: indirect_node保存的是direct_node的nid数组,由于 4000 - 923 - 1018 - 1018 = 1041,而一个direct_node只能保存1018个block,因此可以知道数据位于indirect_node->nid[1]对应的direct_node中
第四步: 计算剩下的的偏移(4000-923-1018-1018-1018=23)找到数据的物理地址位于该direct_node的direct_node->addr[23]中。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。