diff --git a/Cargo.lock b/Cargo.lock index 22c5eeccb71451acf1cb7cbd9313d248dabb7a17..f52bbb85f07e7e6de05861e8a40777625261b3ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1166,7 +1166,7 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" dependencies = [ - "async-lock 3.4.1", + "async-lock", "blocking", "futures-lite 2.6.0", ] @@ -1180,7 +1180,7 @@ dependencies = [ "async-channel 2.3.1", "async-executor", "async-io", - "async-lock 3.4.1", + "async-lock", "blocking", "futures-lite 2.6.0", "once_cell", @@ -1192,7 +1192,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19634d6336019ef220f09fd31168ce5c184b295cbf80345437cc36094ef223ca" dependencies = [ - "async-lock 3.4.1", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", @@ -1204,15 +1204,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "async-lock" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" -dependencies = [ - "event-listener 2.5.3", -] - [[package]] name = "async-lock" version = "3.4.1" @@ -1252,7 +1243,7 @@ checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel 2.3.1", "async-io", - "async-lock 3.4.1", + "async-lock", "async-signal", "async-task", "blocking", @@ -1281,7 +1272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io", - "async-lock 3.4.1", + "async-lock", "atomic-waker", "cfg-if", "futures-core", @@ -1302,7 +1293,7 @@ dependencies = [ "async-channel 1.9.0", "async-global-executor", "async-io", - "async-lock 3.4.1", + "async-lock", "async-process", "crossbeam-utils", "futures-channel", @@ -6538,15 +6529,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "fs_benchmarks" -version = "0.1.0" -dependencies = [ - "fs", - "gpui", - "workspace-hack", -] - [[package]] name = "fs_extra" version = "1.3.0" @@ -11053,7 +11035,7 @@ dependencies = [ "ashpd 0.12.0", "async-fs", "async-io", - "async-lock 3.4.1", + "async-lock", "blocking", "cbc", "cipher", @@ -15754,7 +15736,7 @@ dependencies = [ "async-executor", "async-fs", "async-io", - "async-lock 3.4.1", + "async-lock", "async-net", "async-process", "blocking", @@ -20868,7 +20850,6 @@ name = "worktree" version = "0.1.0" dependencies = [ "anyhow", - "async-lock 2.8.0", "clock", "collections", "fs", @@ -20899,17 +20880,6 @@ dependencies = [ "zlog", ] -[[package]] -name = "worktree_benchmarks" -version = "0.1.0" -dependencies = [ - "fs", - "gpui", - "settings", - "workspace-hack", - "worktree", -] - [[package]] name = "write16" version = "1.0.0" @@ -21181,7 +21151,7 @@ dependencies = [ "async-broadcast", "async-executor", "async-io", - "async-lock 3.4.1", + "async-lock", "async-process", "async-recursion", "async-task", diff --git a/Cargo.toml b/Cargo.toml index 5482e20a1b2230b3c10ba043a2bf5c71d9a4cc25..3e4d3d18483583dd592df38deac4ed7b4e6dfee8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -222,7 +222,7 @@ members = [ "tooling/perf", "tooling/workspace-hack", - "tooling/xtask", "crates/fs_benchmarks", "crates/worktree_benchmarks", + "tooling/xtask", ] default-members = ["crates/zed"] @@ -455,7 +455,6 @@ async-compat = "0.2.1" async-compression = { version = "0.4", features = ["gzip", "futures-io"] } async-dispatcher = "0.1" async-fs = "2.1" -async-lock = "2.1" async-pipe = { git = "https://github.com/zed-industries/async-pipe-rs", rev = "82d00a04211cf4e1236029aa03e6b6ce2a74c553" } async-recursion = "1.0.0" async-tar = "0.5.0" diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 2c8dc9e3548fa5edd2cc3020f1a314e961bd71a3..c627f1852cf4562fa366ab7caae695e8495700a9 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -12509,7 +12509,6 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) { ) .await; - cx.run_until_parked(); // Set up a buffer white some trailing whitespace and no trailing newline. cx.set_state( &[ diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index 9907d0dcbde489b4f4de57133baf299ad0be14a1..81483ce56ce270b595fc06cb3d5b3246a29032b8 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -7,7 +7,6 @@ pub mod fs_watcher; use anyhow::{Context as _, Result, anyhow}; #[cfg(any(target_os = "linux", target_os = "freebsd"))] use ashpd::desktop::trash; -use futures::stream::iter; use gpui::App; use gpui::BackgroundExecutor; use gpui::Global; @@ -563,17 +562,12 @@ impl Fs for RealFs { async fn load(&self, path: &Path) -> Result { let path = path.to_path_buf(); - self.executor - .spawn(async move { Ok(std::fs::read_to_string(path)?) }) - .await + let text = smol::unblock(|| std::fs::read_to_string(path)).await?; + Ok(text) } - async fn load_bytes(&self, path: &Path) -> Result> { let path = path.to_path_buf(); - let bytes = self - .executor - .spawn(async move { std::fs::read(path) }) - .await?; + let bytes = smol::unblock(|| std::fs::read(path)).await?; Ok(bytes) } @@ -641,46 +635,30 @@ impl Fs for RealFs { if let Some(path) = path.parent() { self.create_dir(path).await?; } - let path = path.to_owned(); - let contents = content.to_owned(); - self.executor - .spawn(async move { - std::fs::write(path, contents)?; - Ok(()) - }) - .await + smol::fs::write(path, content).await?; + Ok(()) } async fn canonicalize(&self, path: &Path) -> Result { - let path = path.to_owned(); - self.executor - .spawn(async move { - std::fs::canonicalize(&path).with_context(|| format!("canonicalizing {path:?}")) - }) + Ok(smol::fs::canonicalize(path) .await + .with_context(|| format!("canonicalizing {path:?}"))?) } async fn is_file(&self, path: &Path) -> bool { - let path = path.to_owned(); - self.executor - .spawn(async move { std::fs::metadata(path).is_ok_and(|metadata| metadata.is_file()) }) + smol::fs::metadata(path) .await + .is_ok_and(|metadata| metadata.is_file()) } async fn is_dir(&self, path: &Path) -> bool { - let path = path.to_owned(); - self.executor - .spawn(async move { std::fs::metadata(path).is_ok_and(|metadata| metadata.is_dir()) }) + smol::fs::metadata(path) .await + .is_ok_and(|metadata| metadata.is_dir()) } async fn metadata(&self, path: &Path) -> Result> { - let path_buf = path.to_owned(); - let symlink_metadata = match self - .executor - .spawn(async move { std::fs::symlink_metadata(&path_buf) }) - .await - { + let symlink_metadata = match smol::fs::symlink_metadata(path).await { Ok(metadata) => metadata, Err(err) => { return match (err.kind(), err.raw_os_error()) { @@ -691,28 +669,19 @@ impl Fs for RealFs { } }; + let path_buf = path.to_path_buf(); + let path_exists = smol::unblock(move || { + path_buf + .try_exists() + .with_context(|| format!("checking existence for path {path_buf:?}")) + }) + .await?; let is_symlink = symlink_metadata.file_type().is_symlink(); - let metadata = if is_symlink { - let path_buf = path.to_path_buf(); - let path_exists = self - .executor - .spawn(async move { - path_buf - .try_exists() - .with_context(|| format!("checking existence for path {path_buf:?}")) - }) - .await?; - if path_exists { - let path_buf = path.to_path_buf(); - self.executor - .spawn(async move { std::fs::metadata(path_buf) }) - .await - .with_context(|| "accessing symlink for path {path}")? - } else { - symlink_metadata - } - } else { - symlink_metadata + let metadata = match (is_symlink, path_exists) { + (true, true) => smol::fs::metadata(path) + .await + .with_context(|| "accessing symlink for path {path}")?, + _ => symlink_metadata, }; #[cfg(unix)] @@ -738,11 +707,7 @@ impl Fs for RealFs { } async fn read_link(&self, path: &Path) -> Result { - let path = path.to_owned(); - let path = self - .executor - .spawn(async move { std::fs::read_link(&path) }) - .await?; + let path = smol::fs::read_link(path).await?; Ok(path) } @@ -750,13 +715,7 @@ impl Fs for RealFs { &self, path: &Path, ) -> Result>>>> { - let path = path.to_owned(); - let result = iter( - self.executor - .spawn(async move { std::fs::read_dir(path) }) - .await?, - ) - .map(|entry| match entry { + let result = smol::fs::read_dir(path).await?.map(|entry| match entry { Ok(entry) => Ok(entry.path()), Err(error) => Err(anyhow!("failed to read dir entry {error:?}")), }); diff --git a/crates/fs_benchmarks/Cargo.toml b/crates/fs_benchmarks/Cargo.toml deleted file mode 100644 index 2372db36c894281f83861475090c6bf43baf97c7..0000000000000000000000000000000000000000 --- a/crates/fs_benchmarks/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "fs_benchmarks" -version = "0.1.0" -publish.workspace = true -edition.workspace = true - -[dependencies] -fs.workspace = true -gpui = {workspace = true, features = ["windows-manifest"]} -workspace-hack.workspace = true - -[lints] -workspace = true diff --git a/crates/fs_benchmarks/LICENSE-GPL b/crates/fs_benchmarks/LICENSE-GPL deleted file mode 120000 index 89e542f750cd3860a0598eff0dc34b56d7336dc4..0000000000000000000000000000000000000000 --- a/crates/fs_benchmarks/LICENSE-GPL +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE-GPL \ No newline at end of file diff --git a/crates/fs_benchmarks/src/main.rs b/crates/fs_benchmarks/src/main.rs deleted file mode 100644 index 12df32f0763e02a95c3f261d2c14fa6e295c304e..0000000000000000000000000000000000000000 --- a/crates/fs_benchmarks/src/main.rs +++ /dev/null @@ -1,32 +0,0 @@ -use fs::Fs; -use gpui::{AppContext, Application}; -fn main() { - let Some(path_to_read) = std::env::args().nth(1) else { - println!("Expected path to read as 1st argument."); - return; - }; - - let _ = Application::headless().run(|cx| { - let fs = fs::RealFs::new(None, cx.background_executor().clone()); - cx.background_spawn(async move { - let timer = std::time::Instant::now(); - let result = fs.load_bytes(path_to_read.as_ref()).await; - let elapsed = timer.elapsed(); - if let Err(e) = result { - println!("Failed `load_bytes` after {elapsed:?} with error `{e}`"); - } else { - println!("Took {elapsed:?} to read {} bytes", result.unwrap().len()); - }; - let timer = std::time::Instant::now(); - let result = fs.metadata(path_to_read.as_ref()).await; - let elapsed = timer.elapsed(); - if let Err(e) = result { - println!("Failed `metadata` after {elapsed:?} with error `{e}`"); - } else { - println!("Took {elapsed:?} to query metadata"); - }; - std::process::exit(0); - }) - .detach(); - }); -} diff --git a/crates/worktree/Cargo.toml b/crates/worktree/Cargo.toml index 611091c11ff724ad43570f653b1c3644400f1f09..fdeca37b7ac73759fe9851f722985349e0a183b7 100644 --- a/crates/worktree/Cargo.toml +++ b/crates/worktree/Cargo.toml @@ -24,7 +24,6 @@ test-support = [ [dependencies] anyhow.workspace = true -async-lock.workspace = true clock.workspace = true collections.workspace = true fs.workspace = true diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index d3aa911ae27c97ffaeb1933c27d8a40d4869fe77..003aeb133b20560db8ab5948a9b1105c617b5b4d 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -64,7 +64,7 @@ use std::{ use sum_tree::{Bias, Dimensions, Edit, KeyedItem, SeekTarget, SumTree, Summary, TreeMap, TreeSet}; use text::{LineEnding, Rope}; use util::{ - ResultExt, debug_panic, maybe, + ResultExt, debug_panic, paths::{PathMatcher, PathStyle, SanitizedPath, home_dir}, rel_path::RelPath, }; @@ -226,7 +226,7 @@ impl Default for WorkDirectory { } } -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct LocalSnapshot { snapshot: Snapshot, global_gitignore: Option>, @@ -239,7 +239,6 @@ pub struct LocalSnapshot { /// The file handle of the worktree root. `None` if the worktree is a directory. /// (so we can find it after it's been moved) root_file_handle: Option>, - executor: BackgroundExecutor, } struct BackgroundScannerState { @@ -322,6 +321,7 @@ impl DerefMut for LocalSnapshot { } } +#[derive(Debug)] enum ScanState { Started, Updated { @@ -402,7 +402,6 @@ impl Worktree { PathStyle::local(), ), root_file_handle, - executor: cx.background_executor().clone(), }; let worktree_id = snapshot.id(); @@ -1070,7 +1069,7 @@ impl LocalWorktree { scan_requests_rx, path_prefixes_to_scan_rx, next_entry_id, - state: async_lock::Mutex::new(BackgroundScannerState { + state: Mutex::new(BackgroundScannerState { prev_snapshot: snapshot.snapshot.clone(), snapshot, scanned_dirs: Default::default(), @@ -2443,7 +2442,7 @@ impl LocalSnapshot { log::trace!("insert entry {:?}", entry.path); if entry.is_file() && entry.path.file_name() == Some(&GITIGNORE) { let abs_path = self.absolutize(&entry.path); - match self.executor.block(build_gitignore(&abs_path, fs)) { + match smol::block_on(build_gitignore(&abs_path, fs)) { Ok(ignore) => { self.ignores_by_parent_abs_path .insert(abs_path.parent().unwrap().into(), (Arc::new(ignore), true)); @@ -2494,12 +2493,7 @@ impl LocalSnapshot { inodes } - async fn ignore_stack_for_abs_path( - &self, - abs_path: &Path, - is_dir: bool, - fs: &dyn Fs, - ) -> IgnoreStack { + fn ignore_stack_for_abs_path(&self, abs_path: &Path, is_dir: bool, fs: &dyn Fs) -> IgnoreStack { let mut new_ignores = Vec::new(); let mut repo_root = None; for (index, ancestor) in abs_path.ancestors().enumerate() { @@ -2510,8 +2504,9 @@ impl LocalSnapshot { new_ignores.push((ancestor, None)); } } - - let metadata = fs.metadata(&ancestor.join(DOT_GIT)).await.ok().flatten(); + let metadata = smol::block_on(fs.metadata(&ancestor.join(DOT_GIT))) + .ok() + .flatten(); if metadata.is_some() { repo_root = Some(Arc::from(ancestor)); break; @@ -2657,7 +2652,7 @@ impl BackgroundScannerState { .any(|p| entry.path.starts_with(p)) } - async fn enqueue_scan_dir( + fn enqueue_scan_dir( &self, abs_path: Arc, entry: &Entry, @@ -2665,10 +2660,7 @@ impl BackgroundScannerState { fs: &dyn Fs, ) { let path = entry.path.clone(); - let ignore_stack = self - .snapshot - .ignore_stack_for_abs_path(&abs_path, true, fs) - .await; + let ignore_stack = self.snapshot.ignore_stack_for_abs_path(&abs_path, true, fs); let mut ancestor_inodes = self.snapshot.ancestor_inodes_for_path(&path); if !ancestor_inodes.contains(&entry.inode) { @@ -2706,17 +2698,11 @@ impl BackgroundScannerState { } } - async fn insert_entry( - &mut self, - mut entry: Entry, - fs: &dyn Fs, - watcher: &dyn Watcher, - ) -> Entry { + fn insert_entry(&mut self, mut entry: Entry, fs: &dyn Fs, watcher: &dyn Watcher) -> Entry { self.reuse_entry_id(&mut entry); let entry = self.snapshot.insert_entry(entry, fs); if entry.path.file_name() == Some(&DOT_GIT) { - self.insert_git_repository(entry.path.clone(), fs, watcher) - .await; + self.insert_git_repository(entry.path.clone(), fs, watcher); } #[cfg(test)] @@ -2847,7 +2833,7 @@ impl BackgroundScannerState { self.snapshot.check_invariants(false); } - async fn insert_git_repository( + fn insert_git_repository( &mut self, dot_git_path: Arc, fs: &dyn Fs, @@ -2888,11 +2874,10 @@ impl BackgroundScannerState { fs, watcher, ) - .await .log_err(); } - async fn insert_git_repository_for_path( + fn insert_git_repository_for_path( &mut self, work_directory: WorkDirectory, dot_git_abs_path: Arc, @@ -2914,7 +2899,7 @@ impl BackgroundScannerState { let work_directory_abs_path = self.snapshot.work_directory_abs_path(&work_directory); let (repository_dir_abs_path, common_dir_abs_path) = - discover_git_paths(&dot_git_abs_path, fs).await; + discover_git_paths(&dot_git_abs_path, fs); watcher .add(&common_dir_abs_path) .context("failed to add common directory to watcher") @@ -3558,7 +3543,7 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey { } struct BackgroundScanner { - state: async_lock::Mutex, + state: Mutex, fs: Arc, fs_case_sensitive: bool, status_updates_tx: UnboundedSender, @@ -3584,39 +3569,31 @@ impl BackgroundScanner { // If the worktree root does not contain a git repository, then find // the git repository in an ancestor directory. Find any gitignore files // in ancestor directories. - let root_abs_path = self.state.lock().await.snapshot.abs_path.clone(); + let root_abs_path = self.state.lock().snapshot.abs_path.clone(); let (ignores, repo) = discover_ancestor_git_repo(self.fs.clone(), &root_abs_path).await; self.state .lock() - .await .snapshot .ignores_by_parent_abs_path .extend(ignores); - let containing_git_repository = if let Some((ancestor_dot_git, work_directory)) = repo { - maybe!(async { - self.state - .lock() - .await - .insert_git_repository_for_path( - work_directory, - ancestor_dot_git.clone().into(), - self.fs.as_ref(), - self.watcher.as_ref(), - ) - .await - .log_err()?; - Some(ancestor_dot_git) - }) - .await - } else { - None - }; + let containing_git_repository = repo.and_then(|(ancestor_dot_git, work_directory)| { + self.state + .lock() + .insert_git_repository_for_path( + work_directory, + ancestor_dot_git.clone().into(), + self.fs.as_ref(), + self.watcher.as_ref(), + ) + .log_err()?; + Some(ancestor_dot_git) + }); log::trace!("containing git repository: {containing_git_repository:?}"); let mut global_gitignore_events = if let Some(global_gitignore_path) = &paths::global_gitignore_path() { - self.state.lock().await.snapshot.global_gitignore = + self.state.lock().snapshot.global_gitignore = if self.fs.is_file(&global_gitignore_path).await { build_gitignore(global_gitignore_path, self.fs.as_ref()) .await @@ -3630,34 +3607,31 @@ impl BackgroundScanner { .await .0 } else { - self.state.lock().await.snapshot.global_gitignore = None; + self.state.lock().snapshot.global_gitignore = None; Box::pin(futures::stream::empty()) }; let (scan_job_tx, scan_job_rx) = channel::unbounded(); { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.scan_id += 1; if let Some(mut root_entry) = state.snapshot.root_entry().cloned() { - let ignore_stack = state - .snapshot - .ignore_stack_for_abs_path(root_abs_path.as_path(), true, self.fs.as_ref()) - .await; + let ignore_stack = state.snapshot.ignore_stack_for_abs_path( + root_abs_path.as_path(), + true, + self.fs.as_ref(), + ); if ignore_stack.is_abs_path_ignored(root_abs_path.as_path(), true) { root_entry.is_ignored = true; - state - .insert_entry(root_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()) - .await; + state.insert_entry(root_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()); } if root_entry.is_dir() { - state - .enqueue_scan_dir( - root_abs_path.as_path().into(), - &root_entry, - &scan_job_tx, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + root_abs_path.as_path().into(), + &root_entry, + &scan_job_tx, + self.fs.as_ref(), + ); } } }; @@ -3666,11 +3640,11 @@ impl BackgroundScanner { drop(scan_job_tx); self.scan_dirs(true, scan_job_rx).await; { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.completed_scan_id = state.snapshot.scan_id; } - self.send_status_update(false, SmallVec::new()).await; + self.send_status_update(false, SmallVec::new()); // Process any any FS events that occurred while performing the initial scan. // For these events, update events cannot be as precise, because we didn't @@ -3715,7 +3689,7 @@ impl BackgroundScanner { if did_scan { let abs_path = { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.path_prefixes_to_scan.insert(request.path.clone()); state.snapshot.absolutize(&request.path) }; @@ -3724,7 +3698,7 @@ impl BackgroundScanner { self.process_events(vec![abs_path]).await; } } - self.send_status_update(false, request.done).await; + self.send_status_update(false, request.done); } paths = fs_events_rx.next().fuse() => { @@ -3753,7 +3727,7 @@ impl BackgroundScanner { request.relative_paths.sort_unstable(); self.forcibly_load_paths(&request.relative_paths).await; - let root_path = self.state.lock().await.snapshot.abs_path.clone(); + let root_path = self.state.lock().snapshot.abs_path.clone(); let root_canonical_path = self.fs.canonicalize(root_path.as_path()).await; let root_canonical_path = match &root_canonical_path { Ok(path) => SanitizedPath::new(path), @@ -3775,7 +3749,7 @@ impl BackgroundScanner { .collect::>(); { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let is_idle = state.snapshot.completed_scan_id == state.snapshot.scan_id; state.snapshot.scan_id += 1; if is_idle { @@ -3792,12 +3766,12 @@ impl BackgroundScanner { ) .await; - self.send_status_update(scanning, request.done).await + self.send_status_update(scanning, request.done) } async fn process_events(&self, mut abs_paths: Vec) { log::trace!("process events: {abs_paths:?}"); - let root_path = self.state.lock().await.snapshot.abs_path.clone(); + let root_path = self.state.lock().snapshot.abs_path.clone(); let root_canonical_path = self.fs.canonicalize(root_path.as_path()).await; let root_canonical_path = match &root_canonical_path { Ok(path) => SanitizedPath::new(path), @@ -3805,7 +3779,6 @@ impl BackgroundScanner { let new_path = self .state .lock() - .await .snapshot .root_file_handle .clone() @@ -3838,31 +3811,24 @@ impl BackgroundScanner { let mut dot_git_abs_paths = Vec::new(); abs_paths.sort_unstable(); abs_paths.dedup_by(|a, b| a.starts_with(b)); - { - let snapshot = &self.state.lock().await.snapshot; - abs_paths.retain(|abs_path| { + abs_paths.retain(|abs_path| { let abs_path = &SanitizedPath::new(abs_path); - + let snapshot = &self.state.lock().snapshot; { let mut is_git_related = false; - let dot_git_paths = self.executor.block(maybe!(async { - let mut path = None; - for ancestor in abs_path.as_path().ancestors() { - - if is_git_dir(ancestor, self.fs.as_ref()).await { + let dot_git_paths = abs_path.as_path().ancestors().find_map(|ancestor| { + if smol::block_on(is_git_dir(ancestor, self.fs.as_ref())) { let path_in_git_dir = abs_path .as_path() .strip_prefix(ancestor) .expect("stripping off the ancestor"); - path = Some((ancestor.to_owned(), path_in_git_dir.to_owned())); - break; - } + Some((ancestor.to_owned(), path_in_git_dir.to_owned())) + } else { + None } - path - - })); + }); if let Some((dot_git_abs_path, path_in_git_dir)) = dot_git_paths { if skipped_files_in_dot_git @@ -3935,12 +3901,12 @@ impl BackgroundScanner { true } }); - } + if relative_paths.is_empty() && dot_git_abs_paths.is_empty() { return; } - self.state.lock().await.snapshot.scan_id += 1; + self.state.lock().snapshot.scan_id += 1; let (scan_job_tx, scan_job_rx) = channel::unbounded(); log::debug!("received fs events {:?}", relative_paths); @@ -3954,29 +3920,29 @@ impl BackgroundScanner { .await; let affected_repo_roots = if !dot_git_abs_paths.is_empty() { - self.update_git_repositories(dot_git_abs_paths).await + self.update_git_repositories(dot_git_abs_paths) } else { Vec::new() }; { - let mut ignores_to_update = self.ignores_needing_update().await; + let mut ignores_to_update = self.ignores_needing_update(); ignores_to_update.extend(affected_repo_roots); - let ignores_to_update = self.order_ignores(ignores_to_update).await; - let snapshot = self.state.lock().await.snapshot.clone(); + let ignores_to_update = self.order_ignores(ignores_to_update); + let snapshot = self.state.lock().snapshot.clone(); self.update_ignore_statuses_for_paths(scan_job_tx, snapshot, ignores_to_update) .await; self.scan_dirs(false, scan_job_rx).await; } { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.completed_scan_id = state.snapshot.scan_id; for (_, entry) in mem::take(&mut state.removed_entries) { state.scanned_dirs.remove(&entry.id); } } - self.send_status_update(false, SmallVec::new()).await; + self.send_status_update(false, SmallVec::new()); } async fn update_global_gitignore(&self, abs_path: &Path) { @@ -3985,30 +3951,30 @@ impl BackgroundScanner { .log_err() .map(Arc::new); let (prev_snapshot, ignore_stack, abs_path) = { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); state.snapshot.global_gitignore = ignore; let abs_path = state.snapshot.abs_path().clone(); - let ignore_stack = state - .snapshot - .ignore_stack_for_abs_path(&abs_path, true, self.fs.as_ref()) - .await; + let ignore_stack = + state + .snapshot + .ignore_stack_for_abs_path(&abs_path, true, self.fs.as_ref()); (state.snapshot.clone(), ignore_stack, abs_path) }; let (scan_job_tx, scan_job_rx) = channel::unbounded(); self.update_ignore_statuses_for_paths( scan_job_tx, prev_snapshot, - vec![(abs_path, ignore_stack)], + vec![(abs_path, ignore_stack)].into_iter(), ) .await; self.scan_dirs(false, scan_job_rx).await; - self.send_status_update(false, SmallVec::new()).await; + self.send_status_update(false, SmallVec::new()); } async fn forcibly_load_paths(&self, paths: &[Arc]) -> bool { let (scan_job_tx, scan_job_rx) = channel::unbounded(); { - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let root_path = state.snapshot.abs_path.clone(); for path in paths { for ancestor in path.ancestors() { @@ -4016,14 +3982,12 @@ impl BackgroundScanner { && entry.kind == EntryKind::UnloadedDir { let abs_path = root_path.join(ancestor.as_std_path()); - state - .enqueue_scan_dir( - abs_path.into(), - entry, - &scan_job_tx, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + abs_path.into(), + entry, + &scan_job_tx, + self.fs.as_ref(), + ); state.paths_to_scan.insert(path.clone()); break; } @@ -4035,7 +3999,7 @@ impl BackgroundScanner { self.scan_dir(&job).await.log_err(); } - !mem::take(&mut self.state.lock().await.paths_to_scan).is_empty() + !mem::take(&mut self.state.lock().paths_to_scan).is_empty() } async fn scan_dirs( @@ -4083,7 +4047,7 @@ impl BackgroundScanner { ) { Ok(_) => { last_progress_update_count += 1; - self.send_status_update(true, SmallVec::new()).await; + self.send_status_update(true, SmallVec::new()); } Err(count) => { last_progress_update_count = count; @@ -4108,12 +4072,8 @@ impl BackgroundScanner { .await; } - async fn send_status_update( - &self, - scanning: bool, - barrier: SmallVec<[barrier::Sender; 1]>, - ) -> bool { - let mut state = self.state.lock().await; + fn send_status_update(&self, scanning: bool, barrier: SmallVec<[barrier::Sender; 1]>) -> bool { + let mut state = self.state.lock(); if state.changed_paths.is_empty() && scanning { return true; } @@ -4142,7 +4102,7 @@ impl BackgroundScanner { let root_abs_path; let root_char_bag; { - let snapshot = &self.state.lock().await.snapshot; + let snapshot = &self.state.lock().snapshot; if self.settings.is_path_excluded(&job.path) { log::error!("skipping excluded directory {:?}", job.path); return Ok(()); @@ -4195,14 +4155,12 @@ impl BackgroundScanner { }; if child_name == DOT_GIT { - let mut state = self.state.lock().await; - state - .insert_git_repository( - child_path.clone(), - self.fs.as_ref(), - self.watcher.as_ref(), - ) - .await; + let mut state = self.state.lock(); + state.insert_git_repository( + child_path.clone(), + self.fs.as_ref(), + self.watcher.as_ref(), + ); } else if child_name == GITIGNORE { match build_gitignore(&child_abs_path, self.fs.as_ref()).await { Ok(ignore) => { @@ -4222,7 +4180,7 @@ impl BackgroundScanner { if self.settings.is_path_excluded(&child_path) { log::debug!("skipping excluded child entry {child_path:?}"); - self.state.lock().await.remove_path(&child_path); + self.state.lock().remove_path(&child_path); continue; } @@ -4322,7 +4280,7 @@ impl BackgroundScanner { new_entries.push(child_entry); } - let mut state = self.state.lock().await; + let mut state = self.state.lock(); // Identify any subdirectories that should not be scanned. let mut job_ix = 0; @@ -4404,7 +4362,7 @@ impl BackgroundScanner { None }; - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let doing_recursive_update = scan_queue_tx.is_some(); // Remove any entries for paths that no longer exist or are being recursively @@ -4420,10 +4378,11 @@ impl BackgroundScanner { let abs_path: Arc = root_abs_path.join(path.as_std_path()).into(); match metadata { Ok(Some((metadata, canonical_path))) => { - let ignore_stack = state - .snapshot - .ignore_stack_for_abs_path(&abs_path, metadata.is_dir, self.fs.as_ref()) - .await; + let ignore_stack = state.snapshot.ignore_stack_for_abs_path( + &abs_path, + metadata.is_dir, + self.fs.as_ref(), + ); let is_external = !canonical_path.starts_with(&root_canonical_path); let mut fs_entry = Entry::new( path.clone(), @@ -4455,22 +4414,18 @@ impl BackgroundScanner { || (fs_entry.path.is_empty() && abs_path.file_name() == Some(OsStr::new(DOT_GIT))) { - state - .enqueue_scan_dir( - abs_path, - &fs_entry, - scan_queue_tx, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + abs_path, + &fs_entry, + scan_queue_tx, + self.fs.as_ref(), + ); } else { fs_entry.kind = EntryKind::UnloadedDir; } } - state - .insert_entry(fs_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()) - .await; + state.insert_entry(fs_entry.clone(), self.fs.as_ref(), self.watcher.as_ref()); if path.is_empty() && let Some((ignores, repo)) = new_ancestor_repo.take() @@ -4485,7 +4440,6 @@ impl BackgroundScanner { self.fs.as_ref(), self.watcher.as_ref(), ) - .await .log_err(); } } @@ -4524,11 +4478,11 @@ impl BackgroundScanner { &self, scan_job_tx: Sender, prev_snapshot: LocalSnapshot, - ignores_to_update: Vec<(Arc, IgnoreStack)>, + mut ignores_to_update: impl Iterator, IgnoreStack)>, ) { let (ignore_queue_tx, ignore_queue_rx) = channel::unbounded(); { - for (parent_abs_path, ignore_stack) in ignores_to_update { + while let Some((parent_abs_path, ignore_stack)) = ignores_to_update.next() { ignore_queue_tx .send_blocking(UpdateIgnoreStatusJob { abs_path: parent_abs_path, @@ -4569,11 +4523,11 @@ impl BackgroundScanner { .await; } - async fn ignores_needing_update(&self) -> Vec> { + fn ignores_needing_update(&self) -> Vec> { let mut ignores_to_update = Vec::new(); { - let snapshot = &mut self.state.lock().await.snapshot; + let snapshot = &mut self.state.lock().snapshot; let abs_path = snapshot.abs_path.clone(); snapshot .ignores_by_parent_abs_path @@ -4601,27 +4555,26 @@ impl BackgroundScanner { ignores_to_update } - async fn order_ignores(&self, mut ignores: Vec>) -> Vec<(Arc, IgnoreStack)> { + fn order_ignores( + &self, + mut ignores: Vec>, + ) -> impl use<> + Iterator, IgnoreStack)> { let fs = self.fs.clone(); - let snapshot = self.state.lock().await.snapshot.clone(); + let snapshot = self.state.lock().snapshot.clone(); ignores.sort_unstable(); let mut ignores_to_update = ignores.into_iter().peekable(); - - let mut result = vec![]; - while let Some(parent_abs_path) = ignores_to_update.next() { + std::iter::from_fn(move || { + let parent_abs_path = ignores_to_update.next()?; while ignores_to_update .peek() .map_or(false, |p| p.starts_with(&parent_abs_path)) { ignores_to_update.next().unwrap(); } - let ignore_stack = snapshot - .ignore_stack_for_abs_path(&parent_abs_path, true, fs.as_ref()) - .await; - result.push((parent_abs_path, ignore_stack)); - } - - result + let ignore_stack = + snapshot.ignore_stack_for_abs_path(&parent_abs_path, true, fs.as_ref()); + Some((parent_abs_path, ignore_stack)) + }) } async fn update_ignore_status(&self, job: UpdateIgnoreStatusJob, snapshot: &LocalSnapshot) { @@ -4653,7 +4606,7 @@ impl BackgroundScanner { return; }; - if let Ok(Some(metadata)) = self.fs.metadata(&job.abs_path.join(DOT_GIT)).await + if let Ok(Some(metadata)) = smol::block_on(self.fs.metadata(&job.abs_path.join(DOT_GIT))) && metadata.is_dir { ignore_stack.repo_root = Some(job.abs_path.clone()); @@ -4673,16 +4626,14 @@ impl BackgroundScanner { // Scan any directories that were previously ignored and weren't previously scanned. if was_ignored && !entry.is_ignored && entry.kind.is_unloaded() { - let state = self.state.lock().await; + let state = self.state.lock(); if state.should_scan_directory(&entry) { - state - .enqueue_scan_dir( - abs_path.clone(), - &entry, - &job.scan_queue, - self.fs.as_ref(), - ) - .await; + state.enqueue_scan_dir( + abs_path.clone(), + &entry, + &job.scan_queue, + self.fs.as_ref(), + ); } } @@ -4706,7 +4657,7 @@ impl BackgroundScanner { } } - let state = &mut self.state.lock().await; + let state = &mut self.state.lock(); for edit in &entries_by_path_edits { if let Edit::Insert(entry) = edit && let Err(ix) = state.changed_paths.binary_search(&entry.path) @@ -4722,9 +4673,9 @@ impl BackgroundScanner { state.snapshot.entries_by_id.edit(entries_by_id_edits, ()); } - async fn update_git_repositories(&self, dot_git_paths: Vec) -> Vec> { + fn update_git_repositories(&self, dot_git_paths: Vec) -> Vec> { log::trace!("reloading repositories: {dot_git_paths:?}"); - let mut state = self.state.lock().await; + let mut state = self.state.lock(); let scan_id = state.snapshot.scan_id; let mut affected_repo_roots = Vec::new(); for dot_git_dir in dot_git_paths { @@ -4754,15 +4705,13 @@ impl BackgroundScanner { return Vec::new(); }; affected_repo_roots.push(dot_git_dir.parent().unwrap().into()); - state - .insert_git_repository( - RelPath::new(relative, PathStyle::local()) - .unwrap() - .into_arc(), - self.fs.as_ref(), - self.watcher.as_ref(), - ) - .await; + state.insert_git_repository( + RelPath::new(relative, PathStyle::local()) + .unwrap() + .into_arc(), + self.fs.as_ref(), + self.watcher.as_ref(), + ); } Some(local_repository) => { state.snapshot.git_repositories.update( @@ -4790,7 +4739,7 @@ impl BackgroundScanner { if exists_in_snapshot || matches!( - self.fs.metadata(&entry.common_dir_abs_path).await, + smol::block_on(self.fs.metadata(&entry.common_dir_abs_path)), Ok(Some(_)) ) { @@ -5549,13 +5498,11 @@ fn parse_gitfile(content: &str) -> anyhow::Result<&Path> { Ok(Path::new(path.trim())) } -async fn discover_git_paths(dot_git_abs_path: &Arc, fs: &dyn Fs) -> (Arc, Arc) { +fn discover_git_paths(dot_git_abs_path: &Arc, fs: &dyn Fs) -> (Arc, Arc) { let mut repository_dir_abs_path = dot_git_abs_path.clone(); let mut common_dir_abs_path = dot_git_abs_path.clone(); - if let Some(path) = fs - .load(dot_git_abs_path) - .await + if let Some(path) = smol::block_on(fs.load(dot_git_abs_path)) .ok() .as_ref() .and_then(|contents| parse_gitfile(contents).log_err()) @@ -5564,19 +5511,17 @@ async fn discover_git_paths(dot_git_abs_path: &Arc, fs: &dyn Fs) -> (Arc

>(), final_snapshot.entries(true, 0).collect::>(), - "wrong updates after snapshot {i}: {updates:#?}", + "wrong updates after snapshot {i}: {snapshot:#?} {updates:#?}", ); } } diff --git a/crates/worktree_benchmarks/Cargo.toml b/crates/worktree_benchmarks/Cargo.toml deleted file mode 100644 index 6fcb66fea856cf2e47db5e79680eb83fb8c85a30..0000000000000000000000000000000000000000 --- a/crates/worktree_benchmarks/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "worktree_benchmarks" -version = "0.1.0" -publish.workspace = true -edition.workspace = true - -[dependencies] -fs.workspace = true -gpui = { workspace = true, features = ["windows-manifest"] } -settings.workspace = true -worktree.workspace = true -workspace-hack = { version = "0.1", path = "../../tooling/workspace-hack" } - -[lints] -workspace = true diff --git a/crates/worktree_benchmarks/LICENSE-GPL b/crates/worktree_benchmarks/LICENSE-GPL deleted file mode 120000 index 89e542f750cd3860a0598eff0dc34b56d7336dc4..0000000000000000000000000000000000000000 --- a/crates/worktree_benchmarks/LICENSE-GPL +++ /dev/null @@ -1 +0,0 @@ -../../LICENSE-GPL \ No newline at end of file diff --git a/crates/worktree_benchmarks/src/main.rs b/crates/worktree_benchmarks/src/main.rs deleted file mode 100644 index ca86687aff2d4f5f060ca620205dba5d8da6a73a..0000000000000000000000000000000000000000 --- a/crates/worktree_benchmarks/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::{ - path::Path, - sync::{Arc, atomic::AtomicUsize}, -}; - -use fs::RealFs; -use gpui::Application; -use settings::Settings; -use worktree::{Worktree, WorktreeSettings}; - -fn main() { - let Some(worktree_root_path) = std::env::args().nth(1) else { - println!( - "Missing path to worktree root\nUsage: bench_background_scan PATH_TO_WORKTREE_ROOT" - ); - return; - }; - let app = Application::headless(); - - app.run(|cx| { - settings::init(cx); - WorktreeSettings::register(cx); - let fs = Arc::new(RealFs::new(None, cx.background_executor().clone())); - - cx.spawn(async move |cx| { - let worktree = Worktree::local( - Path::new(&worktree_root_path), - true, - fs, - Arc::new(AtomicUsize::new(0)), - cx, - ) - .await - .expect("Worktree initialization to succeed"); - let did_finish_scan = worktree - .update(cx, |this, _| this.as_local().unwrap().scan_complete()) - .unwrap(); - let start = std::time::Instant::now(); - did_finish_scan.await; - let elapsed = start.elapsed(); - let (files, directories) = worktree - .read_with(cx, |this, _| (this.file_count(), this.dir_count())) - .unwrap(); - println!( - "{:?} for {directories} directories and {files} files", - elapsed - ); - cx.update(|cx| { - cx.quit(); - }) - }) - .detach(); - }) -}