From ed3c9c4f3c8926ecce59ad82c05ec4b460f545b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Sun, 19 Jan 2025 19:48:34 +0800 Subject: [PATCH] perf: detach the watch registration from the main thread (#2224) --- yazi-core/src/manager/watcher.rs | 52 +++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/yazi-core/src/manager/watcher.rs b/yazi-core/src/manager/watcher.rs index 6c9f40d1..3fea308b 100644 --- a/yazi-core/src/manager/watcher.rs +++ b/yazi-core/src/manager/watcher.rs @@ -96,28 +96,17 @@ impl Watcher { }); } - async fn fan_in(mut rx: watch::Receiver>, mut watcher: impl notify::Watcher) { + async fn fan_in( + mut rx: watch::Receiver>, + mut watcher: impl notify::Watcher + Send + 'static, + ) { loop { - let (mut to_unwatch, mut to_watch): (HashSet<_>, HashSet<_>) = { + let (to_unwatch, to_watch): (HashSet<_>, HashSet<_>) = { let (new, old) = (&*rx.borrow_and_update(), &*WATCHED.read()); (old.difference(new).cloned().collect(), new.difference(old).cloned().collect()) }; - to_unwatch.retain(|u| match watcher.unwatch(u) { - Ok(_) => true, - Err(e) if matches!(e.kind, notify::ErrorKind::WatchNotFound) => true, - Err(e) => { - error!("Unwatch failed: {e:?}"); - false - } - }); - to_watch.retain(|u| watcher.watch(u, RecursiveMode::NonRecursive).is_ok()); - - { - let mut watched = WATCHED.write(); - watched.retain(|u| !to_unwatch.contains(u)); - watched.extend(to_watch); - } + watcher = Self::sync_watched(watcher, to_unwatch, to_watch).await; if !rx.has_changed().unwrap_or(false) { Self::sync_linked().await; @@ -173,6 +162,35 @@ impl Watcher { } } + async fn sync_watched(mut watcher: W, to_unwatch: HashSet, to_watch: HashSet) -> W + where + W: notify::Watcher + Send + 'static, + { + use notify::ErrorKind::WatchNotFound; + + if to_unwatch.is_empty() && to_watch.is_empty() { + return watcher; + } + + tokio::task::spawn_blocking(move || { + for u in to_unwatch { + match watcher.unwatch(&u) { + Ok(()) => _ = WATCHED.write().remove(&u), + Err(e) if matches!(e.kind, WatchNotFound) => _ = WATCHED.write().remove(&u), + Err(e) => error!("Unwatch failed: {e:?}"), + } + } + for u in to_watch { + if watcher.watch(&u, RecursiveMode::NonRecursive).is_ok() { + WATCHED.write().insert(u); + } + } + watcher + }) + .await + .unwrap() + } + async fn sync_linked() { let mut new = WATCHED.read().clone();