Skip to content

feat(storage): implement appendable upload background worker#6001

Draft
vsharonlynn wants to merge 3 commits into
googleapis:mainfrom
vsharonlynn:appendable_upload_3_2
Draft

feat(storage): implement appendable upload background worker#6001
vsharonlynn wants to merge 3 commits into
googleapis:mainfrom
vsharonlynn:appendable_upload_3_2

Conversation

@vsharonlynn

Copy link
Copy Markdown
Contributor

This PR comes after #5956.

@product-auto-label product-auto-label Bot added the api: storage Issues related to the Cloud Storage API. label Jul 8, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the internal infrastructure for Appendable Object Write (Bidi Write) in Google Cloud Storage, including a Connector to handle the initial handshake and redirects, and a background Worker to manage the live gRPC stream and upload intents. The feedback highlights two key issues: first, preconditions (if_metageneration_match and if_metageneration_not_match) are lost when transitioning from WriteObjectSpec to AppendObjectSpec in the connector; second, the worker exits silently with Ok(()) if the server closes the stream unexpectedly while the client is idle, which should instead be treated as an error.

Comment on lines +277 to +293
AppendObjectSpecState::Write(s, _) => {
AppendObjectSpecState::Append(AppendObjectSpec {
bucket: s
.resource
.as_ref()
.map(|r| r.bucket.clone())
.unwrap_or_default(),
object: s
.resource
.as_ref()
.map(|r| r.name.clone())
.unwrap_or_default(),
generation: new_generation.unwrap_or(0),
write_handle: m.write_handle.clone(),
..Default::default()
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Preconditions (if_metageneration_match and if_metageneration_not_match) are lost when transitioning from WriteObjectSpec to AppendObjectSpec upon successful connection. This can cause preconditions to be silently ignored if a reconnect happens later. Copy these fields from s to the new AppendObjectSpec to preserve them.

                    AppendObjectSpecState::Write(s, _) => {
                        AppendObjectSpecState::Append(AppendObjectSpec {
                            bucket: s
                                .resource
                                .as_ref()
                                .map(|r| r.bucket.clone())
                                .unwrap_or_default(),
                            object: s
                                .resource
                                .as_ref()
                                .map(|r| r.name.clone())
                                .unwrap_or_default(),
                            generation: new_generation.unwrap_or(0),
                            write_handle: m.write_handle.clone(),
                            if_metageneration_match: s.if_metageneration_match,
                            if_metageneration_not_match: s.if_metageneration_not_match,
                            ..Default::default()
                        })
                    }

Comment on lines +135 to +142
Ok(None) => {
if !self.pending_flushes.is_empty() {
return Some(Err(Arc::new(crate::Error::io(
"stream closed unexpectedly",
))));
}
return None;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the server closes the stream unexpectedly while the client is idle (i.e., pending_flushes is empty), handle_response returns None, which causes the worker to exit silently with Ok(()). This can make subsequent client writes fail with a generic channel closed error instead of a descriptive stream closed error.

Consider tracking whether the upload has been finalized (e.g., via a completed flag set when Finalize is processed), and treat any stream close (Ok(None)) before finalization as an error.

@codecov

codecov Bot commented Jul 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.03974% with 45 lines in your changes missing coverage. Please review.
✅ Project coverage is 97.73%. Comparing base (affbeb2) to head (701a7eb).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
src/storage/src/storage/bidi_write/worker.rs 78.90% 27 Missing ⚠️
src/storage/src/storage/bidi_write/connector.rs 97.25% 14 Missing ⚠️
src/storage/src/storage/bidi_write/redirect.rs 95.50% 4 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #6001    +/-   ##
========================================
  Coverage   97.73%   97.73%            
========================================
  Files         244      247     +3     
  Lines       61096    61832   +736     
========================================
+ Hits        59710    60434   +724     
- Misses       1386     1398    +12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api: storage Issues related to the Cloud Storage API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant