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:
parent
1ecd13ba50
commit
8f942bf647
6 changed files with 69 additions and 79 deletions
|
@ -12,19 +12,13 @@ use std::os::unix::fs::MetadataExt;
|
|||
use async_tar::Archive;
|
||||
use futures::{future::BoxFuture, AsyncRead, Stream, StreamExt};
|
||||
use git::repository::{GitRepository, RealGitRepository};
|
||||
use git2::Repository as LibGitRepository;
|
||||
use parking_lot::Mutex;
|
||||
use rope::Rope;
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use smol::io::AsyncReadExt;
|
||||
use smol::io::AsyncWriteExt;
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
io,
|
||||
io::{self, Write},
|
||||
path::{Component, Path, PathBuf},
|
||||
pin::Pin,
|
||||
sync::Arc,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
use tempfile::{NamedTempFile, TempDir};
|
||||
|
@ -36,6 +30,10 @@ use collections::{btree_map, BTreeMap};
|
|||
#[cfg(any(test, feature = "test-support"))]
|
||||
use git::repository::{FakeGitRepositoryState, GitFileStatus};
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use parking_lot::Mutex;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use smol::io::AsyncReadExt;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
use std::ffi::OsStr;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
@ -83,7 +81,7 @@ pub trait Fs: Send + Sync {
|
|||
latency: Duration,
|
||||
) -> Pin<Box<dyn Send + Stream<Item = Vec<PathBuf>>>>;
|
||||
|
||||
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<Mutex<dyn GitRepository>>>;
|
||||
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>>;
|
||||
fn is_fake(&self) -> bool;
|
||||
async fn is_case_sensitive(&self) -> Result<bool>;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
|
@ -506,16 +504,13 @@ impl Fs for RealFs {
|
|||
})))
|
||||
}
|
||||
|
||||
fn open_repo(&self, dotgit_path: &Path) -> Option<Arc<Mutex<dyn GitRepository>>> {
|
||||
LibGitRepository::open(dotgit_path)
|
||||
.log_err()
|
||||
.map::<Arc<Mutex<dyn GitRepository>>, _>(|libgit_repository| {
|
||||
Arc::new(Mutex::new(RealGitRepository::new(
|
||||
libgit_repository,
|
||||
self.git_binary_path.clone(),
|
||||
self.git_hosting_provider_registry.clone(),
|
||||
)))
|
||||
})
|
||||
fn open_repo(&self, dotgit_path: &Path) -> Option<Arc<dyn GitRepository>> {
|
||||
let repo = git2::Repository::open(dotgit_path).log_err()?;
|
||||
Some(Arc::new(RealGitRepository::new(
|
||||
repo,
|
||||
self.git_binary_path.clone(),
|
||||
self.git_hosting_provider_registry.clone(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn is_fake(&self) -> bool {
|
||||
|
@ -1489,7 +1484,7 @@ impl Fs for FakeFs {
|
|||
}))
|
||||
}
|
||||
|
||||
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<Mutex<dyn GitRepository>>> {
|
||||
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>> {
|
||||
let state = self.state.lock();
|
||||
let entry = state.read_path(abs_dot_git).unwrap();
|
||||
let mut entry = entry.lock();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue