feat(rust-client): Add Multipart Upload API#468
Merged
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #468 +/- ##
==========================================
- Coverage 87.76% 87.56% -0.21%
==========================================
Files 80 81 +1
Lines 12621 12896 +275
==========================================
+ Hits 11077 11292 +215
- Misses 1544 1604 +60
☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
This comment was marked as spam.
lcian
commented
May 11, 2026
This comment was marked as spam.
This comment was marked as spam.
5babbfb to
c33ba6f
Compare
93557e1 to
84181ed
Compare
Contributor
matt-codecov
left a comment
There was a problem hiding this comment.
ran out of steam before i could finish reviewing, sorry
matt-codecov
approved these changes
May 26, 2026
Contributor
matt-codecov
left a comment
There was a problem hiding this comment.
accept w comments (including my comments last week)
ab5d578 to
a2496b3
Compare
The test was inheriting the usecase default (zstd) compression but uploading raw uncompressed parts, causing "Unknown frame descriptor" on read-back.
Instead of disabling compression, send properly zstd-compressed parts so the test exercises the multiple_members concatenated-frame decompression path that the client uses for multipart objects.
Allow callers to disable compression at the Usecase level by passing None to with_compression(). Previously the method only accepted a Compression value, making it impossible to set "no compression" as the usecase-wide default. The internal field and compression() accessor are now Option<Compression>. The default remains Compression::Zstd. Per-operation builders are unaffected since they already accepted Option<Compression>. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… test The full_upload_uncompressed test was sending zstd-compressed parts while the upload metadata had compression=None, so GET returned the raw compressed bytes instead of the expected plaintext.
3565150 to
b1e6a42
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b1e6a42. Configure here.
These were carried over from the old base branch during the restack and downgraded several Python dependencies.
Moves the validated `UploadId` newtype and `PartNumber` (`NonZeroU32`) type alias from `objectstore-service` to `objectstore-types` so they can be shared between the server and Rust client. Updates all wire format types to use the stricter types, removing the need for conversions at the server endpoint boundary.
The client methods (put, put_stream, put_read, resume_multipart_upload) accept u32 for part numbers and String for upload IDs, converting to the stricter internal types (PartNumber, UploadId) at the boundary. This keeps the public API simple while maintaining type safety internally.
Replace InvalidArgument with InvalidPartNumber and InvalidUploadId.
Previously fell through to the catch-all 500 Internal Server Error.
lcian
added a commit
that referenced
this pull request
May 29, 2026
⚠️ Stacked on #468 Adds an optional `multipart` config block for stresstest workloads that exercises the new multipart uploads feature. When enabled, writes for objects >1 KiB use multipart uploads with the configured part size and concurrency. This can be used in both `weighted` and `throughput` mode, but not in `batch` mode, as that wouldn't make any sense. Also adds a `README.md` that documents the meaning of all stresstest options and when they can/should be used. Part of FS-343 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
lcian
added a commit
that referenced
this pull request
May 29, 2026
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.

Implements a multipart upload API for the Rust client.
Instead of going for a low-level API where calls match exactly HTTP calls as I've planned initially, I've decided to abstract some things, for example, initiating a multipart upload returns a
MultipartUploadthat represents it, much like the existingSessionwe have.Please look at the README to see the intended usage.
Also makes a couple changes that aren't strictly related to the multipart upload impl:
objectstore-servertoobjectstore-types, to make them usable from the client too, given that they both deal with the wire format.part_numberwhen callingListParts, as opposed to aBTreeMap.Usecase::compressiontake anOption<Compression>. This is a breaking change that makes it possible to disable default-compression on a usecase, which wasn't possible before.Close FS-357