-
Notifications
You must be signed in to change notification settings - Fork 450
feat(storage): Add full object checksum validation for appendable uploads #16110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
9002525
a4b0911
98ca160
3b3374b
a93f333
51d453a
808392e
58d4b1d
8167423
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -138,10 +138,14 @@ AsyncWriterConnectionImpl::Finalize(storage::WritePayload payload) { | |||||
|
|
||||||
| auto p = WritePayloadImpl::GetImpl(payload); | ||||||
| auto size = p.size(); | ||||||
| auto action = request_.has_append_object_spec() || | ||||||
| request_.write_object_spec().appendable() | ||||||
| ? PartialUpload::kFinalize | ||||||
| : PartialUpload::kFinalizeWithChecksum; | ||||||
| auto action = PartialUpload::kFinalizeWithChecksum; | ||||||
| if (request_.has_append_object_spec() || | ||||||
| request_.write_object_spec().appendable()) { | ||||||
| if (!absl::holds_alternative<google::storage::v2::Object>( | ||||||
| persisted_state_)) { | ||||||
| action = PartialUpload::kFinalize; | ||||||
| } | ||||||
| } | ||||||
| auto coro = PartialUpload::Call(impl_, hash_function_, std::move(write), | ||||||
| std::move(p), std::move(action)); | ||||||
| return coro->Start().then([coro, size, this](auto f) mutable { | ||||||
|
|
@@ -256,7 +260,26 @@ future<StatusOr<std::int64_t>> AsyncWriterConnectionImpl::OnQuery( | |||||
| latest_write_handle_ = response->write_handle(); | ||||||
| } | ||||||
| if (response->has_persisted_size()) { | ||||||
| absl::optional<google::storage::v2::Object> old_obj; | ||||||
| if (absl::holds_alternative<google::storage::v2::Object>( | ||||||
| persisted_state_)) { | ||||||
| old_obj = absl::get<google::storage::v2::Object>(persisted_state_); | ||||||
| } | ||||||
|
|
||||||
| persisted_state_ = response->persisted_size(); | ||||||
|
|
||||||
| if (response->has_persisted_data_checksums()) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible that: if a connection retry is triggered during the session, and the server's reported persisted_size causes a resend that overlaps with (but is not exactly aligned to) the client's previous chunk boundaries, the request fails?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the request will fail if we try to send overlapping data.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC, in writer_connection_resumed.cc, when a resume occurs, the client removes the already-persisted bytes from its local buffer and updates its internal google-cloud-cpp/google/cloud/storage/internal/async/writer_connection_resumed.cc Line 451 in a899f46
If the server's persisted_size is not aligned with the client's original chunk boundaries, the client will resend a chunk starting from the new persisted_offset. If this chunk is large enough to extend past the old
This is an edge case but if the fix is straightforward, pls include it in this PR. |
||||||
| auto const& checksums = response->persisted_data_checksums(); | ||||||
| if (checksums.has_crc32c()) { | ||||||
| google::storage::v2::Object obj; | ||||||
| obj.set_size(response->persisted_size()); | ||||||
| *obj.mutable_checksums() = checksums; | ||||||
| if (old_obj) { | ||||||
| obj.set_generation(old_obj->generation()); | ||||||
| } | ||||||
| persisted_state_ = obj; | ||||||
| } | ||||||
| } | ||||||
| return make_ready_future(make_status_or(response->persisted_size())); | ||||||
| } | ||||||
| if (response->has_resource()) { | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.