一、INode部分
先画了一下类图,比较简单。
1、INode是抽象类,有两个子类,INodeFile和INodeDirectory,对了了file和directory。
INode定义了一些基本属性,如name,parent,modificationTime,accessTime,还有ugi信息等。INode implements Comparable是可比较的,可以通过二分查找找到树状结构中对应的INode。
此外,INode中重要的方法是public final ContentSummary computeContentSummary() ,计算该INode树状结构下的统计数据,如file数,dir数,length等。
INode中还有一个重要方法 static byte[][] getPathComponents(String[] strings) 该方法的作用是获取文件名称,按照seperate 即"/",每个path存在一个byte[]数组中。
2、INodeDirectory定义了Directory,基本属性有private List<INode> children 是所有树状结构底下的INodeFile和INodeDirectory,INodeDirectory的一些重要方法:
(1)INode removeChild(INode node) 通过二分查找找到对应的子INode对象,从children中删除,并返回该对象
(2)void replaceChild(INode newChild) 同上,只不过是替换
(3)private INode getChildINode(byte[] name) 通过二分查找获得INode对象
(4)<T extends INode> T addChild(final T node, boolean inheritPermission) 插入一个INode对象到队列中,并且按顺序插入,其中重要的代码是
int low = Collections.binarySearch(children, node.name); if(low >= 0) return null; node.parent = this;
children.add(-low - 1, node);
(5)<T extends INode> INodeDirectory addToParent 插入一个INode到相关的parent中,并且更新该parent对应的INode children队列
(6)DirCounts spaceConsumedInTree(DirCounts counts) 计算磁盘使用空间,递归计算
(7)int collectSubtreeBlocksAndClear(List<Block> v) 将所有树状结构下的block返回,用于删除以后对block做处理。
(8)int getExistingPathINodes(byte[][] components, INode[] existing) 这个方法个人认为比较重要,作用是从components[]中获取存在的INode数组,意思是components是一个全路径path,有可能存在该路径,也可能不存在,通过该函数找到存在的path,形成INode对象返回
int getExistingPathINodes(byte[][] components, INode[] existing) {
assert compareBytes(this.name, components[0]) == 0 :
"Incorrect name " + getLocalName() + " expected " + components[0];
INode curNode = this;
int count = 0;
int index = existing.length - components.length;
if (index > 0)
index = 0;
while ((count < components.length) && (curNode != null)) {
if (index >= 0)
existing[index] = curNode;
if (!curNode.isDirectory() || (count == components.length - 1))
break; // no more child, stop here
INodeDirectory parentDir = (INodeDirectory)curNode;
curNode = parentDir.getChildINode(components[count + 1]);
count += 1;
index += 1;
}
return count;
}
3、INodeDirectoryWithQuota 继承自INodeDirectory,加入了Quota,如果超出Quota会抛出相应的ExceededException 异常。
4、INodeFile INodeFile对应了Block,HDFS对每个File复制了多分副本,通过策略放在不同的DataNode上,同时每个INodeFile对应了多个Block,默认情况下每个Block64M。
INodeFile中主要的属性有protected BlockInfo blocks[],protected short blockReplication,protected long preferredBlockSize
blocks在blockMap中会详细介绍,就是该INodeFile对应的Block。
INodeFile中的一些重要方法:
(1)Block getLastBlock() 获得最后一个Block,由于目前HDFS支持append,所以获得最后一个Block进行append操作
(2)void addBlock(BlockInfo newblock) 向该INodeFile对应的Block数组中最后位置添加一个Block
(3)int collectSubtreeBlocksAndClear(List<Block> v) 将所有Block放在列表中,如删除某个目录下所有文件,就需要获得所有Block,在BlockMap中进行删除。
int collectSubtreeBlocksAndClear(List<Block> v) { parent = null; for (Block blk : blocks) { v.add(blk); } blocks = null; return 1; }
设置parent=null 使得资源得以通过GC回收。
(4)Block getPenultimateBlock() 获得倒数第二个Block
5、INodeFileUnderConstruction 说明该INodeFile对应的Block正在写入DataNode。INodeFile处于UnderConstruction状态有几种情况,如正写入文件,lease recovery等。当然只能对最后一个Block进行append。
主要属性有 String clientName; 正在写入的Client名称。 private int primaryNodeIndex = -1; 当进行leaseRecovery时,会选出primary通过primary向其它DataNode发送Recovery信息。
private DatanodeDescriptor[] targets = null; target是最后一个Block对应的DataNode位置,该target由一定算法获得。在后面会分析。
重要的方法有:
(1)void setTargets(DatanodeDescriptor[] targets) 设置该INodeFile对应Block所在的DataNode(DatanodeDescriptor是DataNode的抽象)
(2)void addTarget(DatanodeDescriptor node) 将新的DataNode加入到target中
(3)INodeFile convertToInodeFile() 如果DataNode获得所有数据并成功回报给NameNode后,将INodeFIleUnderConstruction状态转化为正常状态。
(4) void removeBlock(Block oldblock) 将最后一个Block删除,原因可能是由于Block传输过程中出错,被abandon掉,也可能是进行recovery中发现时间戳不一致。
(5)synchronized void setLastBlock(BlockInfo newblock, DatanodeDescriptor[] newtargets) 设置最后一个Block,并且设置对应的DataNode,在NameNode的Append中使用。
(6)void assignPrimaryDatanode() 在LeaseRecovery过程中使用,到LeaseRecovery过程会详细解释,这个方法就是找到一个alive的DataNode作为primary,来进行Lease Recovery。
INode部分至此结束,INode+BlockMap构成了NameNode中主要的数据结构,其它的操作都是围绕这这两个数据结构进行处理,后面将会总结BlockMap。