介面 org.apache.hadoop.fs.MultipartUploader

MultipartUploader 可使用多個部分將檔案上傳至 Hadoop 支援的檔案系統。多部分上傳的優點在於,可以從多個用戶端或程序並行上傳檔案,而且在呼叫 complete 函數之前,其他用戶端將看不到結果。

當由物件儲存體實作時,上傳的資料可能會產生儲存費用,即使在檔案系統中尚未顯示。此 API 的使用者必須勤加注意,並始終盡力完成或中止上傳。abortUploadsUnderPath(path) 操作在此情況下會有幫助。

不變式

有效 MultipartUploader 的所有需求都被視為隱含的經濟條件和後置條件

單一多部分上傳作業可能會在多個多部分上傳器實例、多個處理程序和主機上進行。因此,需要

  1. 上傳部分、完成上傳或中止上傳所需的所有狀態都必須包含在或可從上傳處理中擷取。

  2. 該處理必須可序列化;它必須可反序列化為執行 Hadoop 相同版本的不同處理程序。

  3. 不同的主機/處理程序可能會按順序或同時上傳不同的部分。上傳到檔案系統的順序不得限制資料儲存在最終檔案中的順序。

  4. 上傳可以在與上傳部分的任何實例不同的實例上完成。

  5. 上傳的輸出在完成上傳之前不得在最終目的地顯示。

  6. 如果單一多部分上傳器實例按順序啟動或完成上傳多個檔案到相同目的地,則不是錯誤,無論儲存體是否支援同時上傳。

同時執行

多個處理程序可以同時上傳多部分上傳的部分。

如果對正在進行主動上傳的目的地呼叫 startUpload(path),實作必須執行以下兩個作業之一。

  • 拒絕呼叫作為重複呼叫。
  • 允許兩者繼續進行,檔案的最終輸出為 兩個上傳中的一個

哪個上傳會成功是未定義的。使用者不應期待跨檔案系統、跨檔案系統實例 * 甚至跨不同要求的一致行為。

如果在部分上傳進行中完成或中止多部分上傳,則進行中的上傳(如果尚未完成)不得全部或部分包含在最終檔案中。實作應在 putPart() 作業中引發錯誤。

序列化相容性

使用者不得期待序列化 PathHandle 版本與 * 不同的多部分上傳器實作相容。 * 相同實作的不同版本相容。

也就是說:所有用戶端都必須使用 Hadoop 的相同版本。

模型

支援多部分上傳的 FileSystem/FileContext 將現有模型 (目錄、檔案、符號連結) 延伸為 (目錄、檔案、符號連結、上傳) 上傳 類型為 Map[上傳處理 -> Map[部分處理 -> 上傳部分]

狀態組的 上傳 元素是所有主動上傳的對應。

Uploads: Map[UploadHandle -> Map[PartHandle -> UploadPart]`

上傳處理是非空的位元組清單。

UploadHandle: List[byte]
len(UploadHandle) > 0

用戶端 必須 將此視為不透明。此功能設計的核心是,處理在所有用戶端之間都是有效的:處理可以在主機 hostA 上序列化,在 hostB 上反序列化,並仍用於延伸或完成上傳。

UploadPart = (Path: path, parts: Map[PartHandle -> byte[]])

類似地,部分處理 類型也是不透明位元組的非空清單,同樣可以在主機之間封送。

PartHandle: List[byte]

隱含地,FS.Uploads 中的每個 上傳處理 都是唯一的。類似地,[部分處理 -> 上傳部分] 對應中的每個 部分處理 也必須是唯一的。

  1. 沒有要求部分處理在所有上傳中都是唯一的。
  2. 沒有要求上傳處理在一段時間內是唯一的。但是,如果部分處理快速回收,則存在風險,即名義上冪等的作業 abort(FS, 上傳處理) 可能意外取消使用相同上傳處理的後續作業。

非同步 API

所有作業都會傳回 CompletableFuture<> 類型,必須進一步評估才能取得其傳回值。

  1. 作業執行可能會在呼叫執行緒上進行封鎖作業。
  2. 如果不是,則應在獨立執行緒中執行,且必須在未來評估傳回時完成。
  3. 部分/全部前置條件可能會在初始呼叫時評估,
  4. 所有未在當時評估的前置條件,都必須在未來執行期間評估。

這表示,當實作與快速檔案系統/儲存體互動時,所有前置條件(包括檔案存在)可能會提早評估,而與探測速度較慢的遠端物件儲存體互動的實作可能會在非同步階段驗證前置條件,尤其是與遠端儲存體互動的前置條件。

Java CompletableFutures 無法順利與檢查式例外狀況搭配使用。Hadoop 程式碼仍持續演進此處的例外狀況處理細節,因為非同步 API 的使用率越來越高。假設任何宣告必須引發 IOException 的前置條件失敗,可能會在未來評估時將該作業包裝在某種形式的 RuntimeException 中;這也適用於作業期間引發的任何其他 IOException

close()

應用程式必須在使用上傳器後呼叫 close();這是為了讓它可以釋放其他物件、更新統計資料等。

狀態變更作業

CompletableFuture<UploadHandle> startUpload(Path)

開始多部分上傳,最終傳回 UploadHandle 以供後續作業使用。

前置條件

if path == "/" : raise IOException

if exists(FS, path) and not isFile(FS, path) raise PathIsDirectoryException, IOException

如果檔案系統不支援對目的地進行同時上傳,則會新增下列前置條件

if path in values(FS.Uploads) raise PathExistsException, IOException

後置條件

初始化作業完成後,檔案系統狀態會更新為新的主動上傳,並附上新的控制代碼,此控制代碼會傳回給呼叫者。

handle' = UploadHandle where not handle' in keys(FS.Uploads)
FS' = FS where FS'.Uploads(handle') == {}
result = handle'

CompletableFuture<PartHandle> putPart(UploadHandle uploadHandle, int partNumber, Path filePath, InputStream inputStream, long lengthInBytes)

上傳特定多部分上傳的部分,最終會傳回不透明的部分控制代碼,代表指定上傳的此部分。

前置條件

uploadHandle in keys(FS.Uploads)
partNumber >= 1
lengthInBytes >= 0
len(inputStream) >= lengthInBytes

後置條件

data' = inputStream(0..lengthInBytes)
partHandle' = byte[] where not partHandle' in keys(FS.uploads(uploadHandle).parts)
FS' = FS where FS'.uploads(uploadHandle).parts(partHandle') == data'
result = partHandle'

資料會儲存在檔案系統中,待完成後。它絕不能在目的地路徑中可見。它可以在檔案系統中某處的暫時路徑中可見;這是實作特定的,且絕不能依賴它。

CompletableFuture<PathHandle> complete(UploadHandle uploadId, Path filePath, Map<Integer, PartHandle> handles)

完成多部分上傳。

檔案系統可能會強制執行每個部分的最小大小,不包括上傳的最後一個部分。

如果某個部分超出此範圍,則必須引發 IOException

前置條件

uploadHandle in keys(FS.Uploads) else raise FileNotFoundException
FS.Uploads(uploadHandle).path == path
if exists(FS, path) and not isFile(FS, path) raise PathIsDirectoryException, IOException
parts.size() > 0
forall k in keys(parts): k > 0
forall k in keys(parts):
  not exists(k2 in keys(parts)) where (parts[k] == parts[k2])

所有金鑰都必須大於零,並且不能有任何重複的參考指向同一個部分處理。這些驗證可以在操作期間的任何時間點執行。在失敗之後,無法保證具有有效路徑映射的此上傳的 complete() 呼叫會完成。呼叫者應在任何此類失敗後呼叫 abort() 以確保清理。

如果對此 uploadHandle 執行 putPart() 操作,但其 PathHandle 處理未包含在此請求中,則遺漏的部分不應成為結果檔案的一部分。

多部分上傳器必須清理任何此類未完成的項目。

對於支援目錄的後端儲存體(例如本機檔案系統、HDFS 等),如果在完成時,目的地現在有一個目錄,則必須擲出 PathIsDirectoryException 或其他 IOException

後置條件

UploadData' == ordered concatention of all data in the map of parts, ordered by key
exists(FS', path') and result = PathHandle(path')
FS' = FS where FS.Files(path) == UploadData' and not uploadHandle in keys(FS'.uploads)

完成操作會傳回 PathHandle,因此後續操作將能夠識別資料在此期間未變更。

檔案上傳部分的順序與映射中部分的自然順序相同:第 1 部分在第 2 部分之前,依此類推。

CompletableFuture<Void> abort(UploadHandle uploadId, Path filePath)

中止多部分上傳。處理會失效,且無法重新使用。

前置條件

uploadHandle in keys(FS.Uploads) else raise FileNotFoundException

後置條件

上傳處理不再已知。

FS' = FS where not uploadHandle in keys(FS'.uploads)

使用同一個處理對 abort() 的後續呼叫會失敗,除非處理已回收。

CompletableFuture<Integer> abortUploadsUnderPath(Path path)

對路徑下的所有上傳執行盡力清理。

傳回會解析為的未來。

-1 if unsuppported
>= 0 if supported

由於是盡力而為,因此無法有嚴格的後置條件。理想的後置條件是路徑下的所有上傳都已中止,而計數為已中止上傳的數量

FS'.uploads forall upload in FS.uploads:
    not isDescendant(FS, path, upload.path)
return len(forall upload in FS.uploads:
               isDescendant(FS, path, upload.path))