Skip to content

Add cross-provider ranged, parallel downloads#340

Merged
nuwang merged 1 commit into
mainfrom
ranged-parallel-download
Jul 10, 2026
Merged

Add cross-provider ranged, parallel downloads#340
nuwang merged 1 commit into
mainfrom
ranged-parallel-download

Conversation

@nuwang

@nuwang nuwang commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Downloads get the same treatment uploads got in #333. BucketObject.download_to_file(path, config) fetches objects larger than the configured threshold as ranged reads of part_size bytes, up to max_concurrency parts in parallel — large downloads are no longer bound to a single connection, and the whole object is never held in memory (notably fixing GCP, whose iter_content buffered the entire object).

Provider Path
AWS boto3 TransferManager (download_file driven by CloudBridge's knobs)
Azure azure-storage-blob concurrent downloader (download_blob(max_concurrency=…))
GCP generic driver (ranged get_media reads)
OpenStack generic driver (ranged Swift GETs)

The generic driver mirrors the upload driver: parts fetched across a bounded thread pool of cloned providers (no shared SDK state), each worker writing at its offset into a preallocated file, memory bounded to ~concurrency × part_size, and the partial file removed on any failure. A new BucketObjectService.download_range(bucket, object_name, offset, length) primitive backs the driver and is usable directly for partial reads.

UploadConfigTransferConfig: the same threshold/part-size/concurrency knobs now tune both directions (pass a different instance per call to tune each direction separately, mirroring boto3's single TransferConfig). UploadConfig only shipped in 4.2.x and has no downstream users, so it is renamed outright with no alias.

Tests

  • tests/test_download_driver.py: in-memory-fake suite for the generic driver (exact range tiling with short tail, single-shot below threshold, clone-per-worker isolation + real overlap, per-call config precedence, partial-file cleanup on failure, part-size validation)
  • e2e in tests/test_object_store_service.py: small roundtrip, large ranged roundtrip with a position-sensitive byte pattern (all providers), and boto3 TransferConfig wiring assertions (AWS/mock)

Verification

  • tox -e py3.13-mock: full suite green
  • tox -e mypy: clean (interface strict bar enforces the new signatures on all providers)
  • tox -e lint: clean

Live provider runs via the safe-to-test label will exercise the ranged roundtrip against real Azure/GCP/Swift.

BucketObject.download_to_file fetches objects larger than the configured
threshold as ranged reads of part_size bytes, up to max_concurrency
parts in parallel, so large downloads are not bound to a single
connection and the whole object is never held in memory. AWS delegates
to boto3's TransferManager and Azure to azure-storage-blob's concurrent
downloader; GCP and OpenStack Swift use the generic driver, which
fetches ranges in parallel via cloned providers (memory bounded to
~concurrency * part_size; the partial file is removed on failure). A new
BucketObjectService.download_range primitive is also usable directly for
partial reads.

Since the same threshold/part-size/concurrency knobs now tune transfers
in both directions, UploadConfig (shipped only in 4.2.x, unused
downstream) is renamed to TransferConfig with no alias kept.
@nuwang nuwang temporarily deployed to cloud-integration July 10, 2026 18:15 — with GitHub Actions Inactive
@nuwang nuwang temporarily deployed to cloud-integration July 10, 2026 18:15 — with GitHub Actions Inactive
@nuwang nuwang deployed to cloud-integration July 10, 2026 18:15 — with GitHub Actions Active
@nuwang nuwang temporarily deployed to cloud-integration July 10, 2026 18:15 — with GitHub Actions Inactive
@nuwang nuwang merged commit 863d0c8 into main Jul 10, 2026
8 checks passed
@nuwang nuwang deleted the ranged-parallel-download branch July 10, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant