前言
在linux文件系统中,i-node节点一直是一个非常重要的设计,同样在HDFS中,也存在这样的一个类似的角色,不过他是一个全新的类,INode.class,后面的目录类等等都是他的子类。最近学习了部分HDFS的源码结构,就好好理一理这方面的知识,帮助大家更好的从深层次了解Hadoop分布式系统文件。
HDFS文件相关的类设计
在HDFS中与文件相关的类主要有这么几个
1.INode--这个就是最底层的一个类,抽象类,提炼一些文件目录共有的属性。
2.INodeFile--文件节点类,继承自INode,表示一个文件
3.INodeDirectory--文件目录类,也是继承自INode.他的孩子中是文件集也可能是目录
4.INodeDirectoryWithQuota--有配额限制的目录,这是为了适应HDFS中的配额策略。
5.INodeFileUnderConstruction--处于构建状态的文件类,可以从INodeFile中转化而来。
我大体上分为了以上这么几个类,后续将从上述类中挑出部分代码,来了解作者的巧妙的设计思想。
INode
INode基础抽象类,保存了文件,目录都可能会共有的基本属性,如下
/**
* We keep an in-memory representation of the file/block hierarchy.
* This is a base INode class containing common fields for file and
* directory inodes.
*/
abstract class INode implements Comparable<byte[]> {
//文件/目录名称
protected byte[] name;
//父目录
protected INodeDirectory parent;
//最近一次的修改时间
protected long modificationTime;
//最近访问时间
protected long accessTime;
INode作为基础类,在权限控制的设计方面采用了64位的存储方式,前16位保留访问权限设置,中间16~40位保留所属用户组标识符,41~63位保留所属用户标识符。如下
//Only updated by updatePermissionStatus(...).
//Other codes should not modify it.
private long permission;
//使用long整数的64位保存,分3段保存,分别为mode模式控制访问权限,所属组,所属用户
private static enum PermissionStatusFormat {
MODE(0, 16),
GROUP(MODE.OFFSET + MODE.LENGTH, 25),
USER(GROUP.OFFSET + GROUP.LENGTH, 23);
final int OFFSET;
final int LENGTH; //bit length
final long MASK;
PermissionStatusFormat(int offset, int length) {
OFFSET = offset;
LENGTH = length;
MASK = ((-1L) >>> (64 - LENGTH)) << OFFSET;
}
//与掩码计算并右移得到用户标识符
long retrieve(long record) {
return (record & MASK) >>> OFFSET;
}
long combine(long bits, long record) {
return (record & ~MASK) | (bits << OFFSET);
}
}
要获取这些值,需要与内部的掩码值计算并作左右移操作。在这里存储标识符的好处是比纯粹的字符串省了很多的内存,那么HDFS是如何通过标识符数字获取用户组或用户名的呢,答案在下面
/** Get user name */
public String getUserName() {
int n = (int)PermissionStatusFormat.USER.retrieve(permission);
//根据整形标识符,SerialNumberManager对象中取出,避免存储字符串消耗大量内存
return SerialNumberManager.INSTANCE.getUser(n);
}
/** Set user */
protected void setUser(String user) {
int n = SerialNumberManager.INSTANCE.getUserSerialNumber(user);
updatePermissionStatus(PermissionStatusFormat.USER, n);
}
/** Get group name */
public String getGroupName() {
int n = (int)PermissionStatusFormat.GROUP.retrieve(permission);
return SerialNumberManager.INSTANCE.getGroup(n);
}
/** Set group */
protected void setGroup(String group) {
int n = SerialNumberManager.INSTANCE.getGroupSerialNumber(group);
updatePermissionStatus(PermissionStatusFormat.GROUP, n);
}
就是在同一的SerialNumberManager对象中去获取的。还有在这里定义了统一判断根目录的方法,通过判断名称长度是否为0
/**
* Check whether this is the root inode.
* 根节点的判断标准是名字长度为0
*/
boolean isRoot() {
return name.length == 0;
}
在INode的方法中还有一个个人感觉比较特别的设计就是对于空间使用的计数,这里的空间不单单指的是磁盘空间大小这么一个,他还包括了name space命名空间,这都是为了后面的HDFS的配额机制准备的变量。详情请看
/** Simple wrapper for two counters :
* nsCount (namespace consumed) and dsCount (diskspace consumed).
*/
static class DirCounts {
long nsCount = 0;
long dsCount = 0;
/** returns namespace coun