HDFS1.0源代码解析—DataNode启动(一)

11 篇文章 0 订阅

DataNode的启动实在DataNode.java中进行的,具体启动流程如下:    

public static void main(String args[]) {
    secureMain(args, null);
  }

在secureMain中调用createDataNode方法,该方法

public static DataNode createDataNode(String args[],
            Configuration conf, SecureResources resources) throws IOException {
    DataNode dn = instantiateDataNode(args, conf, resources);
    runDatanodeDaemon(dn);
    return dn;
  }
利用instantiateDataNode创建DataNode 对象,通过runDatanodeDaemon
      dn.register();
      dn.dataNodeThread = new Thread(dn, dnThreadName);
      dn.dataNodeThread.setDaemon(true); // needed for JUnit testing
      dn.dataNodeThread.start();

进行DataNode注册,创建线程,设置守护线程,启动线程。

以上就是DataNode主线程启动的过程。

其中,创建创建DataNode 对象的过程如下:

在函数instantiateDataNode中, 调用makeInstance函数

  //获取配置文件中的dfs.data.dir配置的文件路径
   String[] dataDirs = conf.getStrings(DATA_DIR_KEY);
   makeInstance(dataDirs, conf, resources);
在makeInstance函数中,创建dfs.data.dir指定的文件路径,确保至少有一个路径可以被创建,然后调用 DataNode的构造函数。具体如下:

 for (String dir : dataDirs) {
      try {
          //进行用户权限的查询
        DiskChecker.checkDir(localFS, new Path(dir), dataDirPermission);
        //dir存储检查之后的存储文件目录
        dirs.add(new File(dir));
      } catch(IOException e) {
        LOG.warn("Invalid directory in " + DATA_DIR_KEY +  ": " +
                 e.getMessage());
      }
    }
    if (dirs.size() > 0)//至少有一个路径是可创建的
      return new DataNode(conf, dirs, resources);
 DataNode构造函数中调用 startDataNode根据具体配置文件的信息进行具体的初始化过程。 startDataNode具体执行流程如下:

InetSocketAddress nameNodeAddr = NameNode.getServiceAddress(conf, true);

获取配置文件中fs.default.name指定的IP和端口。

    // connect to name node
    this.namenode = (DatanodeProtocol)
      RPC.waitForProxy(DatanodeProtocol.class,
                       DatanodeProtocol.versionID,
                       nameNodeAddr,
                       conf);//通过Hadoop的RPC机制与NameNode进行连接,获取namenode变量,这是DataNode与NameNode进行交互的工具
    // get version and id info from the name-node
    NamespaceInfo nsInfo = handshake();
    StartupOption startOpt = getStartupOption(conf);//获取DataNode启动的模式是regular还是format,如果是第一次启动必须指定format,不指定默认是regular

 static public enum StartupOption{
    FORMAT  ("-format"),
    REGULAR ("-regular"),
    UPGRADE ("-upgrade"),
    ROLLBACK("-rollback"),
    FINALIZE("-finalize"),
    IMPORT  ("-importCheckpoint");
   这些是DataNode可能处于的一些状态。具体状态的切换见另外一篇日志的分析http://blog.csdn.net/zhangchunminggucas/article/details/7556050
 boolean simulatedFSDataset =
        conf.getBoolean("dfs.datanode.simulateddatastorage", false);
    if (simulatedFSDataset) {

这段代码判断是否是伪分布模式。之后会根据data中存储的文件和数据的特点判断是否需要进行恢复、升级、回滚的操作,如果没有按正常流程启动。

 storage.recoverTransitionRead(nsInfo, dataDirs, startOpt);
调用DataStorage类中的recoverTransitionRead进行检查,具体代码如下:

    for(Iterator<File> it = dataDirs.iterator(); it.hasNext();) {
      File dataDir = it.next();
      StorageDirectory sd = new StorageDirectory(dataDir);//初始化storage中的root
      StorageState curState;
      try {
        curState = sd.analyzeStorage(startOpt);
        // sd is locked but not opened
        switch(curState) {
        case NORMAL:
          break;
        case NON_EXISTENT:
          // ignore this storage
          LOG.info("Storage directory " + dataDir + " does not exist.");
          it.remove();
          continue;
        case NOT_FORMATTED: // format
          LOG.info("Storage directory " + dataDir + " is not formatted.");
          LOG.info("Formatting ...");
          format(sd, nsInfo);
          break;
        default:  // recovery part is common
          sd.doRecover(curState);
        }
      } catch (IOException ioe) {
        sd.unlock();
        throw ioe;
      }
      // add to the storage list
      addStorageDir(sd);
      dataDirStates.add(curState);

具体执行是在Storage.java中的analyzeStorage,通过检查返回当前所处的状态,在switch分支中不能处理的分支交与doRecover方法实现。处理完之后会根据StartupOption进行响应的处理,具体由 doTransition(getStorageDir(idx), nsInfo, startOpt);方法执行,该方法的详细解释在另外一篇博客http://blog.csdn.net/zhangchunminggucas/article/details/7556050,最后执行this.writeAll(); 将元信息写入磁盘。

当前DataNode可能处于一下状态:

  public enum StorageState {
    NON_EXISTENT,//数据不存在,不做处理
    NOT_FORMATTED,//没有进行初始化
    COMPLETE_UPGRADE,//完成升级
    RECOVER_UPGRADE,//取消升级
    COMPLETE_FINALIZE,//完成提交
    COMPLETE_ROLLBACK,//取消提交
    RECOVER_ROLLBACK,//取消回滚
    COMPLETE_CHECKPOINT,//NameNode用到,完成checkpoint的恢复
    RECOVER_CHECKPOINT,//取消checkpoint恢复
    NORMAL;//正常启动
  }
analyzeStorage函数是Storage.java中比较重要的一个函数,主要的实现流程是:首先,根据数据目录是否存在和StartupOption选项判断状态是数据不存在还是没有进行初始化。然后根据下面的状态判断DataNode处于的状态,将获得的状态信息返回给recoverTransitionRead进行处理。

     // check whether current directory is valid
      File versionFile = getVersionFile();//获取current下的VERSION文件
      boolean hasCurrent = versionFile.exists();

      // check which directories exist
      boolean hasPrevious = getPreviousDir().exists();
      boolean hasPreviousTmp = getPreviousTmp().exists();
      boolean hasRemovedTmp = getRemovedTmp().exists();
      boolean hasFinalizedTmp = getFinalizedTmp().exists();
      boolean hasCheckpointTmp = getLastCheckpointTmp().exists();
 storage.recoverTransitionRead函数分析完之后,我们继续分析下一个函数 this.data = new FSDataset(storage, conf);在FSDataset构造函数中,主要完成对current目录下文件的遍历,建立volumes、volumeMap、roots。其中volumes是FSVolumeSet对象,用于管理各个FSVolume,每一个data的存储目录(即dfs.data.dirFSVolume指定的每个文件路径)对应一个FSVolume对象,FSVolume对象会记录对应路径的磁盘使用情况,以及 dataDir ,其中this.dataDir = new FSDir(currentDir);管理FSVolume对象对应磁盘路径的目录结构。volumeMap是HashMap<Block,DatanodeBlockInfo>类型的对象,建立的是Block和DatanodeBlockInfo之间的对应关系,其中Block记录blockid、block大小、generationStamp,DatanodeBlockInfo记录对应的FSVolume,block的file对象。
 

























  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值