Hadoop2.6版本的FSImage结构解析

理解FSImage,首先需要理解INode。
下面是Hadoop2.6.0下的INode类图。


Hadoop2.6版本的FSImage结构解析_第1张图片

INode的源码如下
public abstract class INode implements INodeAttributes , Diff.Element< byte []> ,
    AuthorizationProvider.INodeAuthorizationInfo {
    private INode parent = null;
    final boolean isRoot () {
        return getLocalNameBytes(). length == 0 ;
    }

/**
* Information used for updating the blocksMap when deleting files.
*/
public static class BlocksMapUpdateInfo {
  /**
   * The list of blocks that need to be removed from blocksMap
   */
  private final List toDeleteList ;
  ...
}

/**
* INode feature such as { @link FileUnderConstructionFeature}
* and { @link DirectoryWithQuotaFeature}.
*/
public interface Feature {
}

}

属性就一个 parent, 它的作用是在快照当中进行版本判断。其余都是与 INode 权限相关方法。最终要的是有一个内部类 BlocksMapUpdateInfo 用来在删除文件的时候更新 blockMap 。还有一个 Feature 接口,这个 Feature 有多个具体实现如下:
Hadoop2.6版本的FSImage结构解析_第2张图片


可以看出来Feature具体类是用来表现 INode 的特性的, AclFeature 是用来表示ACL的 DirectoryWithQuotaFeature 是用来记录配额信息的, FileUnderConstructionFeature 使用来记录在读取文件的信息的, XAttrFeature 是用来保存额外信息的,下面三个都是和快照实现相关的特性类。

我们可以看到 Feature 是作为 INodeWithAdditionalFields 的具体属性的,这个类做为一个抽象类,在INode基础上增加了作为文件、目录或者软连接所必要的几个信息,具体为
final private long id ;
private byte [] name = null;
private long permission = 0L ;
private long modificationTime = 0L ;
private long accessTime = 0L ;
protected Feature[] features = EMPTY_FEATURE ;

其中大部分属性看名字就知道作用,唯独 permission 具体说明下:
    首先看下 INodeWithAdditionalFields 的源码

static enum PermissionStatusFormat {
  MODE ( null, 16 ) ,
  GROUP ( MODE . BITS , 25 ) ,
  USER ( GROUP . BITS , 23 ) ;

  final LongBitFormat BITS ;

static String getUser ( long permission) {
  final int n = ( int ) USER . BITS .retrieve(permission) ;
  return SerialNumberManager. INSTANCE .getUser(n) ;
}
...

}

已及相关类 LongBitFormat 的源码:
public class LongBitFormat implements Serializable {
  private static final long serialVersionUID = 1L ;

  private final String NAME ;
  /** Bit offset */
  private final int OFFSET ;
  /** Bit length */
  private final int LENGTH ;
  /** Minimum value */
  private final long MIN ;
  /** Maximum value */
  private final long MAX ;
  /** Bit mask */
  private final long MASK ;
}
结合来看很容易知道 permission 用一个 long 型保存了 MODE GROUP USER 三个具体内容。

此外 INodeWithAdditionalFields 抽象类,在 INode 基础上对很多抽象方法进行了实现,主要还是权限相关和特性 Feature 及作为文件、目录软连接用的基础方法。

INodeFile类在 INodeWithAdditionalFields 基础上多了 header 属性和 blocks 属性,其中 header 同父类 INodeWithAdditionalFields permission 一样也是用一个 long 类型记录多个属性值,具体为与文件相关的
PREFERRED_BLOCK_SIZE ( null, 48 , 1 ) ,
REPLICATION ( PREFERRED_BLOCK_SIZE . BITS , 12 , 1 ) ,
STORAGE_POLICY_ID ( REPLICATION . BITS , BlockStoragePolicySuite. ID_BIT_LENGTH ,
    0 ) ;
相信看过Hadoop的一眼就能知道这些代表什么。 blocks 记录的是 INodeFile 和文件块之间的关系(Hadoop中的第一类关系),同时INodeFile类提供了block处理相关的几个方法,因为与fsImage相关性不大,这里就不分析了。

INodeDirectory 类相较于 INodeWithAdditionalFields 只多了一个属性 children ,用来记录层级关系,这样就构成了树状结构。文件夹相关的配额信息等都通过提供的方法写入了 INodeWithAdditionalFields Feature上 了。

INodeSymlink 也只是比 INodeWithAdditionalFields 多了一个属性 symlink 用来标记软连接的目标。


INodeReference是一个抽象类,它拓展自INode类,所以INodeReference及其子类是可以添加到文件系统目录树中以替代原有的INodeFile节点的。INodeReference定义了referred字段,这个字段用于保存当前INodeReference类指向的INode节点,所以WithName和RstReference,referred字段就指向了WithCount对象,对于WithCount,referred指向了真正的INode对象。INodeReference还定义了getReferredINode()方法,在文件系统目录树的操作中,如果判断当前节点是一个引用节点,则会调用getReferredINode()方法获取INodeReference指向的INode对象。
具体源码如下
public   abstract   class   INodeReference  extends   INode {
     private   INode referred; //指向的INode节点
     public   INodeReference(INode parent,INode referred){//这里用到了INode的字段parent
         super (parent);
         this .referred = referred;
     }
//...
}
然后,我们在来看看WithCount类的实现。
WithCount类定义了一个集合字段withNameList用于保存所有指向这个WithCount对象的WithName对象集合。WithCount类还定义了addReference()方法,任何指向WithCount对象的WithName对象以及DstReference对象都需要调用这个方法来添加指向关系。对于指向这个WithCount对象的DstReference对象,addReference()方法会将这个对象设置为自己的父INode节点;而对于WithName对象,addReference()方法则将这个对象放入withNameList集合中保存。
public static class WithCount extends INodeReference {
     //保存所有指向这个WithCount对象的WithName对象的集合     
    private   final   List withNameList =  new   ArrayList();  
     public   WithCount(INodeReference parent,INode referred) {
         super (parent,referred);  //调用父类的构造方法,指向文件系统目录树中的INode
         Preconditions.checkArgument(!referred.isReference());
         refferred.setParentReferenct( this );  //设置真实INode的父节点为当前WithCount对象
     }
      
     public   void   addReferenct(INodeReference ref){
         if   ( ref  instanceof   WithName) {  //如果是WithName对象,则加入withNameList
             WithName refWithName = (WithName) ref;
             in  i = Collections.binarySearch(withNameList, refWithName,WITHNAME_COMPARATOR);
             Preconditions.checkState(i< 0 );
             withNameList.add(-i- 1 ,refWithName);
         else   if   (ref  instanceo  DstReference) {  //如果是DstReference对象,则设置为父节点
             setParentReference(ref);
         }
     }
     //...
}
看完WithCount后,在看看WithName和DstReference。WithName类定义了name字段用于保存重命名前文件的名称,同事定义了lastSnapshotId字段用于保存WithName对象构造时源路径的快照版本号。DstReference类的实现就更简单了,只定义了一个dstSnapshotId字段用于保存重命名操作前目标路径的最新快照的版本号。WithName和DstReference在构造时都会调用父类的构造方法指向WithCount对象,同时还会调用WithCount.addReference()方法配置WithCount对象。
public static class WithName extend INodeReference {
     private   final   byte [] name; //重命名前的文件名
     private   final   int   lastSnapshotId;
     public WithName(INodeDirectory parent,WithCount referred,bytep[] name, in  lastSnapshotId){
         super (parent,referred);  //调用父类构造方法,指向WithCount节点
         this .name = name;
         this .lastSnapshotId = lastSnapshotId;
         referred.addReferenct( this );  //调用WithCount.addReferenct()
      }
      //...
}

public   static   class   DstReference  extends   INodeReference {
     private   final   int   dstSnapshotId;
     public   DstReference (INodeDirectory parent,WithCount referred, fina  int  dstSnapshotId){
     super (parent,referred);
     this .lastSnapshotId = lastSnapshotId;
     referred.addReferenct( this );  //调用WithCount.addReferenct()
   }
   //..
}

快照相关类的解析参考自 http://blog.csdn.net/learnboc/article/details/70258541

看完了INode的类之间的关系及各自的作用那么理解FSImage的结构就容易了。首先上图

Hadoop2.6版本的FSImage结构解析_第3张图片

将内存中INode的相关信息持久化FSImage文件上。
FSImage最开始的8个字节为 MAGIC_HEADER ( value=“HDFSIMG1 ”)
中间为10个sections (通过 FileSummary .parseDelimitedFrom( new ByteArrayInputStream(summaryBytes)) ; 得到FileSummary )
    分别为:{
              0:name:”NS_INFO”             记录HDFS文件系统的全局信息,包括NameSystem的ID,当前已经分配出去的最大BlockID以及TransactionId等信息;具体字段          
              1:name: “INODE"              整个目录树所有节点数据,包括INodeFile/INodeDirectory/INodeSymlink等所有类型节点的属性数据,其中记录了如节点id,节点名称,访问权限,创建和访问时间等等信息;
              2:name: “INODE_DIR"          整个目录树中所有节点之间的父子关系,配合INODE可构建完整的目录树;
              3:name: “FILES_UNDERCONSTRUCTION"  尚未完成写入的文件集合,主要为重启时重建Lease集合;

              4:name: “SNAPSHOT"            记录Snapshot数据,快照是Hadoop 2.1.0引入的新特性,用于数据备份、回滚,以防止因用户误操作导致集群出现数据问题;  
                 
              5:name: “SNAPSHOT_DIFF"       执行快照操作的目录/文件的Diff集合数据,与SNAPSHOT一起构建较完整的快照管理能力;

              6:name: “INODE_REFERENCE"     当目录/文件被操作处于快照,且该目录/文件被重命名后,会存在多条访问路径,INodeReference就是为了解决该问题;
              7:name: “SECRET_MANAGER"      记录DelegationKey和DelegationToken数据,根据DelegationKey及由DelegationToken构造出的DelegationTokenIdentifier方便进一步计算密码,以上数据可以完善所有合法Token集合;
                    
              8:name: “CACHE_MANAGER"       集中式缓存特性全局信息,集中式缓存特性是Hadoop-2.3.0为提升数据读性能引入的新特性;
                      
               9:name: “STRING_TABLE"        字符串到id的映射表,维护目录/文件的Permission字符到ID的映射,节省存储空间;
                            
接下去是summary区域,它主要标识了上面10个section区域各区域的name和在fsimage上的起始位置offset及各区域所占的长度length,此外还记录了fsimage的版本号ondiskVersion布局版本号layoutVersion及解压/压缩器codec


文件最后(占4个字节)记录的是summary信息所占空间的长度信息(通过file.seek(fileLength - FILE_LENGTH_FIELD_SIZE)获得) ;
)。













你可能感兴趣的:(Hadoop2.6版本的FSImage结构解析)