hadoop fs -rmコマンド コードリーディング

hadoop fs -rm コマンドの挙動を詳しく確認する必要があり、コードリーディングを行った。

コード自体は自体は以下に存在しており、他のコマンドの実装も周辺にある。 github.com

実装上、-rm-rmdir-rmr-expungeは全て異なる実装が行われているが、 今回対象としたのは -rm だけである。

  • 引数で与えられたオプションを処理 (-r, -f, -R, -skipTrash, -safely)
  • 引数で与えられたパス文字列を内部で PathData に変換 pathが見つからない場合終了
  • 与えられたパスごとに以下の処理を実行。パスが存在しない場合終了
    • まずディレクトリかどうかを確認。 -r オプションが設定されていない場合にディレクトリを作成しようとすると失敗する
    • ゴミ箱に入れる処理を行う (hdfsでは実際にファイルを削除する前にTrashというゴミ箱に一時的に入る)
    • -skipTrash オプションが存在する場合、処理をスキップ
    • fs.trash.interval が Trashから削除される時間を制御. サーバー側で設定されている場合にはその値を優先する
    • fs.trash.interval が0の場合、Trashに入れずに直接削除する
    • Trashが有効な場合、まずhdfs上の絶対パスに直して、file statusを取得(この時点でgetfileinfoが発行される)
    • 削除対象のパスを完全修飾パスに直す
    • 現在のユーザーのTrashRootを取得する (実行ユーザーのHome Directoryに作成される xxx userで実行する場合 /user/xxx/.Trash )
    • そして現在のTrashのパスは /user/xxx/.Trash/Current である
    • もし、削除対象のパスがTrashRootに存在する場合、既にTrashに入っているので処理をスキップする
    • そして逆にTrashRootを削除しようとする場合、削除できないので例外を投げる
    • 削除対象のファイルがTrashで置かれるパスを計算
    • 以下を最大2回行う
      • fs.mkdirsでtrashRootの親ディレクトリを作成する。作成できない場合はTrash処理を終了
      • ファイルが存在していて作成に失敗した場合は、現在時間をsuffixにしたディレクトリを親に作成することにして失敗を無視してリトライ
      • 削除するファイルの名前で既にTrashに存在する場合も、現在時刻をsuffixにしたファイル名をTrashでのファイル名にする
      • fs.renameでTrashに名前を変更して移動する(これが削除処理にあたる)
      • "Moved: '" + path + "' to trash at: " + trashPath 成功するとこれがログに出る
      • 失敗した場合、コマンドが失敗する
  • Trashに入れれた場合には処理を終了する。そうでない場合続行。
  • -safely オプションが指定されている場合、巨大なディレクトリが削除されるような場合には確認を行い問題なければ削除に進む
  • fs.deleteを実行して、Trashをスキップして完全にファイルを削除する

また、コマンドの実行を細かく調査する際に、サーバー側のaudit logが設定されていればこれを確認することで実際に発行された操作の詳細を確認可能である。

例えば、クライアントで実行したコマンドが hadoop fs -rm -r xxx だった場合でも実際にサーバー側に発行されているのは以下の4つのコマンドである。

20xx-xx-xx xx:xx:xx,xxx INFO FSNamesystem.audit: allowed=true   ugi=xxx (auth:SIMPLE) ip=/xx.xxx.xxx.xx       cmd=getfileinfo src=/xxx        dst=null        perm=null       proto=rpc
20xx-xx-xx xx:xx:xx,xxx INFO FSNamesystem.audit: allowed=true   ugi=xxx (auth:SIMPLE) ip=/xx.xxx.xxx.xx       cmd=getfileinfo src=/xxx       dst=null        perm=null       proto=rpc
20xx-xx-xx xx:xx:xx,xxx INFO FSNamesystem.audit: allowed=true   ugi=xxx (auth:SIMPLE) ip=/xx.xxx.xxx.xx       cmd=getfileinfo src=/xxx       dst=null        perm=null       proto=rpc
20xx-xx-xx xx:xx:xx,xxx INFO FSNamesystem.audit: allowed=true   ugi=xxx (auth:SIMPLE) ip=/xx.xxx.xxx.xx       cmd=mkdirs      src=/user/xxx/.Trash/Current/tmp      dst=null        perm=xxx:supergroup:rwx------ proto=rpc