HDFS源代碼分析之DataNode DirectoryScanner實現

DirectoryScanner

DirectoryScanner的主要任務是定期掃描磁盤上的數據塊,檢查磁盤上的數據塊信息是否與FsDatasetImpl中保存的數據塊信息一致,如果不一致則對FsDatasetImpl中的信息進行更新。

注:DirectoryScanner只檢查內存和磁盤上FINALIZED狀態的數據塊是否一致。
public class DirectoryScanner implements Runnable {
  ...
  // 異步收集磁盤數據塊信息的線程池
  private final ExecutorService reportCompileThreadPool;
  // master線程,定期調用DirectoryScanner.run方法
  private final ScheduledExecutorService masterThread;
  // 數據塊信息與內存元數據的差異,掃描過程中更新,掃描結束後把diffs更新到FsDatasetImpl
  final ScanInfoPerBlockPool diffs = new ScanInfoPerBlockPool();
  ...

DirectoryScanner(DataNode datanode, FsDatasetSpi<?> dataset, Configuration conf) {
  ...
    reportCompileThreadPool = Executors.newFixedThreadPool(threads, 
        new Daemon.DaemonFactory());
    //初始化master線程
    masterThread = new ScheduledThreadPoolExecutor(1,
        new Daemon.DaemonFactory());
  }

void start() {
    ...
    // 定期執行DirectoryScanner的run方法
    masterThread.scheduleAtFixedRate(this, offset, scanPeriodMsecs, 
                                     TimeUnit.MILLISECONDS);
  }

  @Override
  public void run() {
    try {
      if (!shouldRun) {
        //shutdown has been activated
        LOG.warn("this cycle terminating immediately because 'shouldRun' has been deactivated");
        return;
      }

      //We're are okay to run - do it
      reconcile();      
      
    } catch (Exception e) {
      //Log and continue - allows Executor to run again next cycle
      LOG.error("Exception during DirectoryScanner execution - will continue next cycle", e);
    } catch (Error er) {
      //Non-recoverable error - re-throw after logging the problem
      LOG.error("System Error during DirectoryScanner execution - permanently terminating periodic scanner", er);
      throw er;
    }
  }

  void reconcile() throws IOException {
    // 調用scan蒐集磁盤數據塊與內存數據塊的差異信息
    scan();
    for (Entry<String, LinkedList<ScanInfo>> entry : diffs.entrySet()) {
      String bpid = entry.getKey();
      LinkedList<ScanInfo> diff = entry.getValue();
      
      for (ScanInfo info : diff) {
        // 與FsDatasetImpl完成同步
        dataset.checkAndUpdate(bpid, info.getBlockId(), info.getBlockFile(),
            info.getMetaFile(), info.getVolume());
      }
    }
    if (!retainDiffs) clear();
  }
}

DirectoryScanner對象會定期在master線程上出發掃描任務,這個任務由reconcile()方法完成。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章