From 03c8df354795efd7f1c75aba9c49f05c38bceb39 Mon Sep 17 00:00:00 2001
From: feeiyu <158308373+feeiyu@users.noreply.github.com>
Date: Tue, 28 Apr 2026 16:29:21 +0800
Subject: [PATCH] git_graph: Align CommitDataReader with batched commit
processing (#54600)
Self-Review Checklist:
- [X] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [X] Performance impact has been considered and is acceptable
Updated `CommitDataReader::read` from single SHA to batched
input/output.
`run_commit_data_reader` is designed to process requests in batches, but
`CommitDataReader::read` previously only sent one SHA per call. So in
practice, commit data was effectively processed one-by-one from the
caller path.
The temporary debug logs show that batching was not performed
previously.
before:
after:
Release Notes:
- N/A
---------
Co-authored-by: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com>
Co-authored-by: Anthony Eid
---
crates/project/src/git_store.rs | 47 +++++++++++++++++++++++++++------
1 file changed, 39 insertions(+), 8 deletions(-)
diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs
index a6d963bd11..31ad970d6e 100644
--- a/crates/project/src/git_store.rs
+++ b/crates/project/src/git_store.rs
@@ -5236,6 +5236,16 @@ impl Repository {
result_tx: smol::channel::Sender<(Oid, CommitData)>,
background_executor: BackgroundExecutor,
) {
+ async fn receive_commit_data_request(
+ request_rx: &smol::channel::Receiver,
+ ) -> Option {
+ if request_rx.is_closed() && request_rx.is_empty() {
+ future::pending().await
+ } else {
+ request_rx.recv().await.ok()
+ }
+ }
+
let reader = match backend.commit_data_reader() {
Ok(reader) => reader,
Err(error) => {
@@ -5244,19 +5254,38 @@ impl Repository {
}
};
+ let read_commit_data = |sha| reader.read(sha).map(move |result| (sha, result));
+ let mut read_futures = FuturesUnordered::new();
+
loop {
- let timeout = background_executor.timer(std::time::Duration::from_secs(10));
+ if read_futures.is_empty() {
+ let timeout = background_executor.timer(Duration::from_secs(10));
+
+ futures::select_biased! {
+ sha = futures::FutureExt::fuse(receive_commit_data_request(&request_rx)) => {
+ if let Some(sha) = sha {
+ read_futures.push(read_commit_data(sha));
+ }
+ }
+ _ = futures::FutureExt::fuse(timeout) => {
+ break;
+ }
+ }
+ }
+
+ let next_read = read_futures.next().fuse();
+ futures::pin_mut!(next_read);
futures::select_biased! {
- sha = futures::FutureExt::fuse(request_rx.recv()) => {
- let Ok(sha) = sha else {
- break;
+ result = next_read => {
+ let Some((sha, result)) = result else {
+ continue;
};
- match reader.read(sha).await {
+ match result {
Ok(commit_data) => {
if result_tx.send((sha, commit_data)).await.is_err() {
- break;
+ return;
}
}
Err(error) => {
@@ -5264,8 +5293,10 @@ impl Repository {
}
}
}
- _ = futures::FutureExt::fuse(timeout) => {
- break;
+ sha = futures::FutureExt::fuse(receive_commit_data_request(&request_rx)) => {
+ if let Some(sha) = sha {
+ read_futures.push(read_commit_data(sha));
+ }
}
}
}