Use repository mutex more sparingly. Don't hold it while running git status. (#12489)

Previously, each git `Repository` object was held inside of a mutex.
This was needed because libgit2's Repository object is (as one would
expect) not thread safe. But now, the two longest-running git operations
that Zed performs, (`status` and `blame`) do not use libgit2 - they
invoke the `git` executable. For these operations, it's not necessary to
hold a lock on the repository.

In this PR, I've moved our mutex usage so that it only wraps the libgit2
calls, not our `git` subprocess spawns. The main user-facing impact of
this is that the UI is much more responsive when initially opening a
project with a very large git repository (e.g. `chromium`, `webkit`,
`linux`).

Release Notes:

- Improved Zed's responsiveness when initially opening a project
containing a very large git repository.
This commit is contained in:
Max Brunsfeld 2024-05-30 09:37:11 -07:00 committed by GitHub
parent 1ecd13ba50
commit 8f942bf647
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 79 deletions

View file

@ -7856,10 +7856,7 @@ impl Project {
None
} else {
let relative_path = repo.relativize(&snapshot, &path).ok()?;
local_repo_entry
.repo()
.lock()
.load_index_text(&relative_path)
local_repo_entry.repo().load_index_text(&relative_path)
};
Some((buffer, base_text))
}
@ -8194,7 +8191,7 @@ impl Project {
&self,
project_path: &ProjectPath,
cx: &AppContext,
) -> Option<Arc<Mutex<dyn GitRepository>>> {
) -> Option<Arc<dyn GitRepository>> {
self.worktree_for_id(project_path.worktree_id, cx)?
.read(cx)
.as_local()?
@ -8202,10 +8199,7 @@ impl Project {
.local_git_repo(&project_path.path)
}
pub fn get_first_worktree_root_repo(
&self,
cx: &AppContext,
) -> Option<Arc<Mutex<dyn GitRepository>>> {
pub fn get_first_worktree_root_repo(&self, cx: &AppContext) -> Option<Arc<dyn GitRepository>> {
let worktree = self.visible_worktrees(cx).next()?.read(cx).as_local()?;
let root_entry = worktree.root_git_entry()?;
@ -8255,8 +8249,7 @@ impl Project {
cx.background_executor().spawn(async move {
let (repo, relative_path, content) = blame_params?;
let lock = repo.lock();
lock.blame(&relative_path, content)
repo.blame(&relative_path, content)
.with_context(|| format!("Failed to blame {:?}", relative_path.0))
})
} else {