Skip to content

gix-transport: add a download-progress byte counter to http::Options#2706

Open
Nik B (nikicat) wants to merge 1 commit into
GitoxideLabs:mainfrom
nikicat:pr-download-progress
Open

gix-transport: add a download-progress byte counter to http::Options#2706
Nik B (nikicat) wants to merge 1 commit into
GitoxideLabs:mainfrom
nikicat:pr-download-progress

Conversation

@nikicat

Copy link
Copy Markdown
Contributor

The curl backend adds the length of each response-body chunk it receives to an optional Arc<AtomicU64> carried on http::Options. This gives callers a live byte signal for phases the protocol layer reports no progress for — notably the v2 ls-refs advertisement, which on a large-ref mirror is many MiB and can take a long time with no feedback at all (transfer_progress only starts moving once the pack begins).

Headers flow through the separate header() callback, so the counter only ever accumulates body bytes.

Covered by download_progress_counts_response_body_bytes, which drives a handshake against the mock server and asserts the count is non-zero and consistent.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47b4e81782

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "Codex (@codex) review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".

/// (e.g. the v2 `ls-refs` ref advertisement). Cumulative across requests on
/// the same transport; the caller owns resetting it if it wants per-request
/// figures. Only the curl backend honors it.
pub download_progress: Option<Arc<std::sync::atomic::AtomicU64>>,

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.

P1 Badge Mark the exhaustive Options change as breaking

When this is released, any dependent crate constructing http::Options with an exhaustive struct literal now has to add download_progress; STABILITY.md defines that as a breaking change, but the commit subject is not a breaking conventional message as required by the repo instructions, so smart-release/changelog handling can treat this as a normal add instead of a breaking API change.

Useful? React with 👍 / 👎.

io::{Read, Write},
sync::{
Arc,
atomic::{AtomicU64, Ordering},

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.

P2 Badge Use a portable atomic counter type

On targets without native 64-bit atomics, std::sync::atomic::AtomicU64 is unavailable; for example rustc --print cfg --target armv5te-unknown-linux-gnueabi lacks target_has_atomic="64", and this repo already handles that case in gix-status with a portable_atomic fallback. As written, enabling the curl HTTP transport on such targets fails to compile before users can opt out of the new progress counter.

Useful? React with 👍 / 👎.

@nikicat

Nik B (nikicat) commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Both review findings are addressed in the force-push (47b4e81ea6256e72):

  • Breaking-change marking: the commit is now a feat!: conventional message (feat!: add a download-progress byte counter to http::Options), with the breaking nature spelled out in the body — Options is constructible via struct literal, so dependents that name every field must add the new one. Fittingly, gix's own transport_options test destructures Options exhaustively and proved the point; it now names the field and asserts it's never set from configuration.
  • Portable atomics: the counter type is re-exported as http::AtomicU64std's atomic where target_has_atomic = "64", with the same portable-atomic fallback gix-status uses (target-specific dependency), so the curl transport keeps compiling on targets like armv5te.

Curl integration tests (including the new counter test) and the gix transport-options tests pass.

The curl backend now adds the length of each response-body chunk it
receives to an optional `Arc<AtomicU64>` carried on `http::Options`. This
gives callers a live byte signal for phases the protocol layer reports no
progress for — notably the v2 `ls-refs` advertisement, which on a
large-ref mirror is many MiB and can take minutes with no feedback.

Headers flow through the separate `header()` callback, so the counter
only ever accumulates body bytes. Covered by a curl-backend test that
drives a handshake against the mock server and asserts the count is
non-zero.

This is a breaking change: `http::Options` is constructible via a struct
literal (it is not `#[non_exhaustive]`), so dependents that spell out
every field must add the new field.

The counter type is re-exported as `http::AtomicU64`: `std`'s atomic
where the target has native 64-bit atomics, with the same
`portable-atomic` fallback `gix-status` uses everywhere else, so the
curl transport keeps compiling on targets like `armv5te` that lack
64-bit atomics.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant