hadoop fs -get命令源碼分析

Created with Raphaël 2.1.2FsShell::run FsShell::init 初始化FsShell,在工廠類中註冊各種命令對應處理類 op1調用命令處理類的run方法實際是調用的Command::run方法 op2processOptions(args)解析命令行入參進行配置 op3processRawArguments(args) op4 expandArguments(args)將入參中的路徑下的文件進行解析,轉換得到PathData數組 op5 processArguments(pathDatas) op6 pathDatas.hasNext?processArgument(pathData) op7pathData.exist(傳的路徑對應的文件在文件系統是否存在)processPathArgument(item) cond78yesprocessPaths(items) op8items.hasNext?processPath(item),如果item對應爲目錄,且設置了循環遍歷(入參中有-R),循環遍歷,處理完成後調用postProcessPath方法進行後續處理EndprocessNonexistentPath(item) cond78noyesnoyesnoyesno

  本人第一次用markdown畫流程圖,而且還有點小複雜,上圖將就着看吧,結合代碼理解起來相對簡單。。 上圖的流程主要體現的是hadoop fs xxx 提交到集羣后執行的邏輯,當然這裏主要是進入具體代碼後的邏輯,進入代碼前,以上命令主要是調用的$HADOOP_HOME/bin hadoop 這個腳本,通過這個腳本里面邏輯是:

if [ "$COMMAND" = "fs" ] ; then
CLASS=org.apache.hadoop.fs.FsShell
...
exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@"

  顯然通過hadoop fs xxx 調用腳本的時候,後面的fsxxx均是腳本的參數,只是第一個fs是腳本運行判斷調用哪塊邏輯的參數,而後面的參數xxx中則是用於給具體java執行類(這裏是FsShell)的參數。
  上圖流程是hadoop fs xxx這一系列命令提交執行的基本流程,這一塊中涉及到的處理類主要都是繼承自Command.java,主要涉及類的作用如下:

FsShell.java 業務入口
CommandFactory.java 各種不同類型請求的處理類工廠
Command.java FsCommand的父類,是一個抽象類
FsCommand.java 抽象類,代碼註釋說的很清楚:Base class for all "hadoop fs" commands 所有類型請求均繼承自它
PathData.java 文件系統中某個路徑對應的邏輯實體類,封裝了這個路徑所屬文件系統信息、路徑信息、路徑下的文件信息以及文件是否存在等

  以上是一些針對hadoop fs整體處理邏輯設計的基礎類,對於具體的請求類型常用的如:getlsputrm等命令,處理類可以在FsCommand.javaregisterCommands方法中查看到往工廠中註冊的類:

    factory.registerCommands(AclCommands.class);
    factory.registerCommands(CopyCommands.class);
    factory.registerCommands(Count.class);
    factory.registerCommands(Delete.class);
    factory.registerCommands(Display.class);
    factory.registerCommands(FsShellPermissions.class);
    factory.registerCommands(FsUsage.class);
    factory.registerCommands(Ls.class);
    factory.registerCommands(Mkdir.class);
    factory.registerCommands(MoveCommands.class);
    factory.registerCommands(SetReplication.class);
    factory.registerCommands(Stat.class);
    factory.registerCommands(Tail.class);
    factory.registerCommands(Test.class);
    factory.registerCommands(Touch.class);
    factory.registerCommands(SnapshotCommands.class);
    factory.registerCommands(XAttrCommands.class);
  }

  對於開篇的流程圖中,每個不同的業務處理類,主要核心的處理邏輯都在processPath(PathData src)方法中,其它的方法主要是一些流程控制、驗證以及異常處理等,這裏我們挑選get方法對應的CopyCommands.class進行介紹,這個CopyCommands.class類是對於文件複製類命令的合集,其中有registerCommands,這個方法主要就是註冊各類需要處理的類到工廠類中(存在工廠類中的一個HashMap中,後續需要用時直接通過命令行參數如get字符串進行map.get()獲取),其調用順序是FsShell::run->FsShell::init->FsShell::registerCommands->CommandFactory::registerCommands,在工廠類CommandFactory::registerCommands中通過反射調用FsShell::registerCommands中入參FsCommandregisterCommands方法,這個方法也是通過反射的方式調用各個入參類中的registerCommands方法,這就是CopyCommands.classregisterCommands調用的路徑,其它處理類調用註冊邏輯一樣。
  繼續來看CopyCommands.class,其中除了registerCommands,主要就是提供了七個靜態公共類,我們這裏對於get請求,處理類就是Get.class,繼承了一個類叫CommandWithDestination,這裏查看Get.class的代碼,只是實現了processOptions對參數進行設置,核心邏輯在它的父類中,繼續進入父類CommandWithDestination中,發現父類果然是繼承自FsCommand,這裏主要看它的核心處理方法processPath,調用順序:processPath(PathData src)->processPath(PathData src, PathData dst)->copyFileToTarget(PathData src, PathData target),到了copyFileToTarget方法這裏的話,邏輯就十分明瞭了,貼出該部分代碼:

      throws IOException {
    final boolean preserveRawXattrs =
        checkPathsForReservedRaw(src.path, target.path);
    src.fs.setVerifyChecksum(verifyChecksum);
    InputStream in = null;
    try {
      in = src.fs.open(src.path);
      copyStreamToTarget(in, target);
      preserveAttributes(src, target, preserveRawXattrs);
    } finally {
      IOUtils.closeStream(in);
    }
  }

  該部分代碼先獲取了系統設置目標路徑下是否需要保存源文件的元數據信息(例如創建時間、所屬用戶、所屬用戶組等),然後獲取源文件的輸出流,並調用copyStreamToTarget方法將輸出流中內容寫入到目標路徑中,最後再調用preserveAttributes進行基本信息元數據信息的填充。
參考文章:
https://blog.csdn.net/strongyoung88/article/details/68952248

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