feat: parallelize data-link chunk uploads - #654
Draft
georgi-seqera wants to merge 2 commits into
Draft
Conversation
georgi-seqera
requested review from
sabulous,
t0randr and
weronikasosnowskaseqera
August 3, 2026 17:54
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Uploads via
tw data-links uploadnow transfer a file's parts concurrently (default 4 at a time, configurable), instead of strictly one-at-a-time.Along the way this makes the shared progress tracker safe under concurrency, adds a
--silentflag to upload and download, shows elapsed time on the progress bar, and reduces per-part allocation overhead.This is the CLI companion to the Platform expired-credential refresh work — large uploads that previously crawled through parts sequentially now saturate available bandwidth while still recovering from expired signing credentials mid-upload.
Why
--silent), and long uploads benefit from an elapsed-time readout.How
Parallel execution. A shared
uploadPartsInParallelhelper inAbstractProviderUploaderruns part tasks on a bounded pool sizedmin(concurrency, totalParts)(so a small file never spawns more threads than parts). It fails fast — the first failing part cancels the remaining in-flight uploads and propagates the cause (re-asserting the interrupt flag on interruption) so the caller can finalize/abort — and always shuts the pool down.ETagkeyed by part number; the completed-parts list is assembled in ascending order after all parts finish (completion order is nondeterministic).Thread-safe progress (the enabler). Global snapshot/restore is replaced with per-part delta accounting:
ProgressTracker.newPart()hands out aPartProgressthat accumulates only its own bytes and forwards them to the tracker through a smallProgressSinkinterface. A failed attempt rolls back only that part's bytes, so concurrent parts can't corrupt each other's progress. The terminating newline is latched to print exactly once.Also included:
--silentonuploadanddownloadto suppress progress output.TOWER_UPLOAD_SIZE_PART_BYTESoverride for the part size (env var, or same-named system property for in-process tests) — lets us exercise multi-part uploads without multi-hundred-MB fixtures.Usage
Tradeoffs / operational notes
concurrency × 250 MB(default 4 ≈ 1 GB). This is documented in the--concurrencyhelp text. There's intentionally no hard cap —--concurrency 8needs ~2 GB, so give the JVM headroom (-Xmx) on constrained machines.--concurrency 0(or negative) is rejected with a clear error.Compatibility
No changes to command syntax or existing behavior beyond the new opt-in
--concurrency(defaults preserve prior semantics aside from running in parallel) and the additive--silent.--concurrency 1reproduces the previous sequential behavior exactly.