Manual multipart uploads
Use these provider operations when an application needs to save progress and continue an upload in another process. The application owns the remote upload, source identity, successful receipts, checkpoint, and decision to publish or abandon it. No operation starts background work or automatically aborts on error.
For ordinary uploads, use CloudStore.put or CloudStore.MultipartUploadStream. They abort a failed upload, so it cannot be resumed.
Provider operations
All names are qualified; none is exported.
| S3 | Azure Blob Storage |
|---|---|
S3.createmultipartupload(bucket, key) returns an upload ID | No creation request; choose a unique block-ID namespace |
S3.uploadpart(bucket, key, id, number, bytes) returns a receipt | Blobs.stageblock(container, key, block_id, bytes) returns a receipt |
S3.listparts(bucket, key, id) follows all pages | Blobs.listblocks(container, key; state=:all) separates committed and uncommitted blocks |
S3.completemultipartupload(bucket, key, id, receipts) publishes | Blobs.commitblocks(container, key, blocks) publishes an explicit ordered selection |
S3.abortmultipartupload(bucket, key, id) discards the upload | There is no abort operation; do not delete an existing blob to discard staged blocks |
These methods take a store and a literal object key, plus explicit credentials when needed. They do not discover credentials. Request headers are copied. Byte vectors and views are borrowed until the synchronous call returns, including permitted part retries; do not mutate them concurrently.
S3 key support also depends on the installed signer. CloudBase 1.4.10, used with Julia 1.6, incorrectly signs keys that require URL escaping. CloudBase 1.6 supports these keys and requires Julia 1.10 or later.
HTTP timeout and signing options pass through to CloudBase. Operation-owned query, body, service, response_stream, and status_exception options cannot be replaced. Creation and final publication also reserve retry and redirect and disable both. In particular, Azure's final PUT is not automatically retried merely because HTTP normally considers PUT idempotent.
Receipts and inspection
Save the exact S3 receipt from every successful upload: number, quoted opaque etag, byte size, and optional checksums. Completion requires strictly increasing, unique part numbers and does not renumber them. Checksum metadata is preserved for completion; CloudStore does not calculate or verify those checksums. The object ETag returned by completion has its surrounding quotes removed, as with CloudStore.put. A listing adds last_modified, but should not replace the application's acknowledgement ledger. If a part reached the server before its receipt was saved, upload the verified same bytes under the same number again. S3 multipart lifecycle
S3 inspection requests at most 1000 parts per page and rejects malformed or non-advancing pages instead of returning a partial result. Concurrent uploads can change between pages; inspection is not an atomic snapshot. S3's part-size, part-count, encryption, checksum-mode, and permission requirements still apply. Listing may need permissions beyond those used to upload. S3 ListParts
Azure block IDs are canonical Base64 encodings of 1–64 bytes. All IDs for one blob must have equal decoded lengths. Use a unique fixed-length namespace for each upload. A block ID may simultaneously identify different committed and uncommitted bytes. commitblocks preserves the caller's order and selects each entry with :committed, :uncommitted, or :latest; repeated IDs must use the same selector. :latest falls back to committed data when an uncommitted block is missing. Use :uncommitted when resuming a fresh upload to avoid that substitution. Block identity, commit selectors
Azure listings contain no per-block content checksum. ID and size alone cannot prove that a block came from the intended source. Safe reuse requires the application's unique IDs, saved acknowledgements, immutable source, and exclusive ownership of those IDs. Listings are not atomic snapshots of concurrent staging. Uncommitted blocks expire under the provider's retention policy. Azure block inspection
Restarting in another process
The runnable checkpoint example implements one deliberately narrow policy: one nonempty immutable local file, one writer, a new destination, fixed parts of at least 5 MiB, and a caller-owned TOML file. It uses CloudStore, HTTP, and Julia standard libraries. Credentials never enter the checkpoint. Keep the checkpoint private and use a durable checkpoint store if recovery after an OS or storage failure is required; its file replacement does not claim crash-durable persistence.
In the first process, construct store and credentials, then:
include("examples/manual_resume.jl")
ManualResumeExample.start(store, "new-object", "source.bin", "upload.toml";
credentials, initial=(3, 1))After that process exits, reconstruct the same store and credentials in another process. The checkpoint supplies the key, upload ID or block IDs, source hash and layout, and saved receipts:
include("examples/manual_resume.jl")
ManualResumeExample.resume(store, "upload.toml"; credentials)The example checks the full source hash before network requests and each part's hash before uploading. It compares saved acknowledgements against provider inspection, fills missing or unacknowledged parts, and commits in source order. An Azure BlobNotFound response means there are no blocks to reuse, including before the first block was staged or after uncommitted blocks expired. The example uploads the verified source again; other provider errors still stop it. The caller must prevent concurrent source changes and checkpoint writers; hashes do not lock a file or make an untrusted checkpoint safe.
Lost final responses
A timeout or error after publication does not prove the object was rejected. The library does not replay a final request or delete data to roll it back. S3 completion also checks for an error embedded in an HTTP 200 XML response. S3 completion outcomes
The example records committing before sending the final request and refuses a second commit in that state. To recognize successful publication, it checks a unique marker in object metadata, then downloads the inspected version using an ETag condition and compares its bytes with the source hash:
ManualResumeExample.reconcile(store, "upload.toml"; credentials)This example downloads the whole object into memory during reconciliation, so verification can require object-sized memory even though uploads read one part at a time.
If reconciliation fails, stop and investigate the provider state. It does not automatically retry publication. Conditional headers such as If-None-Match and If-Match are available on manual completion; the example requires a new object. Azure commit replaces metadata unless it is supplied again.
API
CloudStore.S3.createmultipartupload — Function
S3.createmultipartupload(bucket, key; credentials=nothing, headers=nothing, contentType=nothing, kwargs...) -> StringStart a caller-owned multipart upload and return its opaque upload ID. No automatic cleanup is registered. Save the ID and successful S3.uploadpart receipts to resume later, or call S3.abortmultipartupload to discard the upload. Creation disables HTTP retries and redirects: a lost response can leave an upload whose ID is unknown. headers is copied and sets object metadata at creation.
CloudStore.S3.uploadpart — Function
S3.uploadpart(bucket, key, upload_id, number, bytes; credentials=nothing, headers=nothing, kwargs...)Upload bytes under a part number in 1:10000, replacing that number if it exists. Return an owned (number, etag, size, checksums) receipt. The quoted ETag and optional checksum values are opaque; persist them for completion. bytes is an AbstractVector{UInt8} borrowed until this synchronous call returns. Headers are copied. A failure does not abort the upload.
CloudStore.S3.listparts — Function
S3.listparts(bucket, key, upload_id; credentials=nothing, headers=nothing, maxparts=1000, kwargs...)Inspect all uploaded parts, following pages of at most maxparts (1–1000). Return records with number, quoted etag, size::Int64, checksums, and last_modified. This is an inventory, not a completion receipt ledger: preserve successful upload receipts and verify caller-owned source identity before reuse. Malformed or non-advancing pages throw instead of returning a partial inventory. Concurrent uploads may change between pages; this is not an atomic snapshot.
CloudStore.S3.completemultipartupload — Function
S3.completemultipartupload(bucket, key, upload_id, receipts; credentials=nothing, headers=nothing, kwargs...) -> AbstractStringPublish acknowledged part receipts in strictly increasing number order, without renumbering them. Each receipt needs number and etag, and may have a checksums dictionary returned by S3.uploadpart. Return the final ETag without quotes. Use completion headers for conditions such as If-None-Match; object metadata belongs on creation. HTTP retries and redirects are disabled. After a lost response, reconcile the destination before another commit. Errors never trigger automatic abort.
CloudStore.S3.abortmultipartupload — Function
S3.abortmultipartupload(bucket, key, upload_id; credentials=nothing, headers=nothing, kwargs...)Discard a caller-owned S3 upload. This does not delete a published object. Stop and join in-flight part uploads before aborting; the provider may require another abort if a part finishes concurrently. Provider errors (including a missing upload) propagate.
CloudStore.Blobs.stageblock — Function
Blobs.stageblock(container, key, block_id, bytes; credentials=nothing, headers=nothing, kwargs...)Stage bytes under a caller-owned, opaque Base64 block ID and return (id, size). IDs must encode 1–64 bytes, with the same decoded length for all blocks of one blob. Reusing an ID replaces its uncommitted bytes. Use a unique fixed-length namespace per upload and save IDs, receipts, and source identity before resuming. bytes is an AbstractVector{UInt8} borrowed until this synchronous call returns; headers are copied. Azure has no abort operation for uncommitted blocks.
CloudStore.Blobs.listblocks — Function
Blobs.listblocks(container, key; state=:all, credentials=nothing, headers=nothing, kwargs...)Inspect :committed, :uncommitted, or :all blocks. Return separate committed and uncommitted vectors of (id, size::Int64), and etag (quoted, or nothing when absent). Committed order is preserved. A block ID can appear in both lists with different data. Listings contain no per-block content checksum and do not prove source identity or provide an atomic snapshot of concurrent staging.
CloudStore.Blobs.commitblocks — Function
Blobs.commitblocks(container, key, blocks; credentials=nothing, headers=nothing, contentType=nothing, kwargs...) -> AbstractStringPublish an ordered collection of (id, state) entries, where state is :committed, :uncommitted, or :latest. Order and repeated IDs are preserved; repeated IDs must use the same state. :latest prefers an uncommitted block and falls back to a committed one. Use :uncommitted when that fallback is unwanted. An empty collection publishes an empty blob. Return the final ETag without quotes.
Headers are copied and may set destination conditions or blob metadata. Commit replaces metadata unless supplied again. HTTP retries and redirects are disabled: after a lost response, reconcile the destination before committing again. Failures do not delete the destination or staged blocks.