Hadoop-0.20.0源代码分析(16)

这里对与org.apache.hadoop.hdfs.server.namenode.FSDirectory类相关的类进行阅读分析。

  • INodeDirectoryWithQuota类

该类org.apache.hadoop.hdfs.server.namenode.INodeDirectoryWithQuota的继承层次关系如下所示:

1、INode抽象类

该类是一个保存在内存中的file/block层次结构,一个基本的INode包含了文件和目录inode的通用域(Field) 。下面看INode类定义的属性:

INode类提供的构造方法如下所示:

 

INode类主要就是针对一个INode的名称、所在目录、修改时间、访问时间、权限这些属性来实现操作的,该类中的方法无非实现对这些属性的操作。另外还包括删除该INode,其它几个抽象方法,如下所示:

2、INodeDirectory类

INodeDirectory类是一个目录INode,因此该类内部定义了一个INode列表。该类定义的属性如下:

可以想象得到,作为一个目录,应该提供从目录中检索得到指定的INode的操作,还有就是对引用该INode的INode进行的一些基本操作。这里就不过多阐述了,可以阅读该类的源代码。

3、INodeDirectoryWithQuota类

INodeDirectoryWithQuota类继承自INodeDirectory类,INodeDirectoryWithQuota类表示具有配额限制的目录INode实现类。我们通过该类中定义的一些与配额有关的属性就能了解到这样一种目录INode有什么样的特点:

  • INodeFileUnderConstruction类

该类的继承层次关系如下所示:

其中,INode类前面已经介绍了,它是一个目录或者文件的INode的抽象。

1、INodeFile类

该类表示一个文件INode,正好与目录INode相对应。因为我们已经阅读分析过目录INode的实现,对该文件INode的实现就比较简单了。看该类的属性:

该类定义了如下几个基本的操作: 

对应的set方法,也存在get实现。

可见,一个INodeFile类实例是不持有任何客户端或者Datanode信息的,就是一个基本的实在的文件。因为在HDFS集群中需要执行计算任务,这要涉及到块的复制等操作,而某些块需要由Namenode调度分派给指定的进程去执行,这就需要一种实体类,既能够包含INodeFile的基本信息,又能够包含与在该INodeFile上执行操作的进程,所以,Hadoop实现了一个INodeFileUnderConstruction类,并在INodeFile类中实现了由INodeFile到INodeFileUnderConstruction的转换,如下所示:

2、INodeFileUnderConstruction类

该类所含有的信息包括与执行计算任务相关的一些属性,如下所示:

通过上面属性信息可以知道,一个INodeFileUnderConstruction文件具有持有操作该文件的进程(客户端)的一些信息,如果客户端进程同时也是HDFS集群中Datanode,它就能够根据租约的有效性来执行与该文件相关的操作,例如复制等。

下面介绍个主要方法:

1)assignPrimaryDatanode方法

INodeFileUnderConstruction类中实现的assignPrimaryDatanode方法,能够将该INodeFileUnderConstruction文件分配给指定的客户端进程,也就是执行租约恢复的操作,并通过setLastRecoveryTime更新最后租约恢复时间lastRecoveryTime。下面是assignPrimaryDatanode方法的实现:

2)removeBlock方法

该类的removeBlock方法从该文件的块列表中删除一个块,并且只能删除列表中的最后一个块。实现如下所示: 

3)convertToInodeFile方法

该方法将一个INodeFileUnderConstruction文件转化为INodeFile文件,如下所示:

  • FSDirectory类

该类org.apache.hadoop.hdfs.server.namenode.FSDirectory用来存储文件系统目录的状态。它处理向磁盘中写入或加载数据,并且对目录中的数据发生的改变记录到日志中。它保存了一个最新的filename->blockset的映射表,并且将它写入到磁盘中。

该类定义的属性如下所示:

该类构造方法如下所示:

通过上面的FSDirectory的构造可以看出,通过FSNamesystem ns访问一个已经存在的DFS的命名空间系统目录,为FSDirectory的根目录rootDir设置访问权限。

下面介绍FSDirectory类的方法,选择几个重要的方法详细分析:

1、加载FSImage映像

方法loadFSImage实现如下所示: 

 

通过该方法,我们可以看到加载一个FSImage映像的过程:首先需要对内存中的FSImage对象进行格式化;然后从将指定存储目录中的EditLog日志文件作用到格式化完成的FSImage内存映像上;最后需要再创建一个空的EditLog日志准备记录对命名空间进行修改的操作,以备检查点进程根据需要将EditLog内容作用到FSImage映像上,保持FSImage总是最新的,保证EditLog与FSImage同步。

2、更新INode文件计数

实现的方法为updateCount,如下所示:

文件系统中的INode(目录或文件)可能因为在执行计算任务过程中,某个INode(树)的内容发生变化,为保证HDFS中文件管理的一致性,在必要的时候需要更新INode的统计数据。

3、向该目录中添加一个孩子INode

实现方法为addChild,如下所示:

4、向namespace中添加一个INode

实现的方法为addNode,如下所示:

上面调用了INodeDirectory类的getExistingPathINodes方法,这里说明一下该方法。

例如,给定一个路径/c1/c2/c3,其中只有/c1/c2是存在的,而/c3不存在,则得到这样一个字节数组["","c1","c2","c3"]。

如果想要执行调用getExistingPathINodes(["","c1","c2"], [?]),则应该使用[c2]填充占位数组;

如果想要执行调用getExistingPathINodes(["","c1","c2","c3"], [?]),则应该使用[null]填充占位数组;

如果想要执行调用getExistingPathINodes(["","c1","c2"], [?,?]),则应该使用[c1,c2]填充占位数组;

如果想要执行调用getExistingPathINodes(["","c1","c2","c3"], [?,?]),则应该使用[c2,null]填充占位数组;

如果想要执行调用getExistingPathINodes(["","c1","c2"], [?,?,?,?]),则应该使用[rootINode,c1,c2,null]填充占位数组;

如果想要执行调用getExistingPathINodes(["","c1","c2","c3"], [?,?,?,?]),则应该使用[rootINode,c1,c2,null]填充占位数组。

对应于上面方法中,对getExistingPathINodes方法的调用,指定一个完整路径components(例如上面的src转化后得到的components数组),执行调用后,会根据上述举例中的规则来对inodes数组进行填充。得到一个inodes数组以后,就可以调用addChild方法向该目录FSDirectory中添加一个child。

5、向文件系统中添加一个文件

实现的方法为addFile,如下所示:

通过该方法,我们了解到,当向namespace中添加一个文件的时候,需要通过FSImage映像获取到其所对应的EditLog日志文件,将对使namespace发生改变的事务记录下来。只要当对namespace执行的操作生效的时候,才会被记录到EditLog日志文件中,如果失败的话是不会登陆日志的。

6、向指定文件中写入块(Block)

如下所示:

可见,每当需要向目录中写入块(Block)的时候,都需要向FSNamesystem的blocksMap映射表中登记,同时通过从FSNamesystem的blocksMap映射表中获取待写入块已经存在的信息,一同写入到该目录中该块所属的文件中去。

7、需要写入EditLog日志文件的操作

这里,对FSDirectory类中实现的,与namespace相关的需要写入到EditLog日志文件的事务进行总结,给出具体的操作说明。

一共涉及到12个操作,执行这些操作的时候,需要登录到EditLog日志中,如下所示:

 

对于FSDirectory类,我们就分析这么多。通过上面分析,我们知道了FSDirectory类主要是管理对于属于一个FSDirectory类目录实例的文件的基本操作,而一个FSDirectory类是位于文件系统中的,对于指定的文件进行的操作都由FSDirectory类来管理维护,并对特定的事务写入到EditLog日志文件中。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页