feat: parallelize data-link chunk uploads - #654
Conversation
sabulous
left a comment
There was a problem hiding this comment.
Besides my only comment, I tested it and it works as expected. Approving to unblock
…nst mismatch with platform on partSize
Good catch! I removed the I'm changed it to a property setting instead for test purposes as I don't want to add to the scope of this PR and I put the guard in for an early warning in case Platform's partSize does ever change. |

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.