summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2023-06-16 21:04:22 +0200
committerGitHub <noreply@github.com>2023-06-16 21:04:22 +0200
commitb7436742cddc3987df46371428d1be0d0ebfa282 (patch)
treeb46981be175fe5a9558f0ed0571717492b651934
parent317bdfc90252058d51b3f2a1847b2074baf5e80e (diff)
performance(plugins): use a debounced fs watcher (#2546)
* performance(plugins): use a debounced fs watcher * style(fmt): rustfmt * fix(macos): use recommended watcher
-rw-r--r--Cargo.lock24
-rw-r--r--zellij-server/src/plugins/wasm_bridge.rs8
-rw-r--r--zellij-server/src/plugins/watch_filesystem.rs145
-rw-r--r--zellij-utils/Cargo.toml2
-rw-r--r--zellij-utils/src/lib.rs4
5 files changed, 127 insertions, 56 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b410d17f4..535879b8d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1006,6 +1006,15 @@ dependencies = [
]
[[package]]
+name = "file-id"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13be71e6ca82e91bc0cb862bebaac0b2d1924a5a1d970c822b2f98b63fda8c3"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
name = "filedescriptor"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1832,6 +1841,19 @@ dependencies = [
]
[[package]]
+name = "notify-debouncer-full"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4812c1eb49be776fb8df4961623bdc01ec9dfdc1abe8211ceb09150a2e64219"
+dependencies = [
+ "crossbeam-channel",
+ "file-id",
+ "notify",
+ "parking_lot 0.12.1",
+ "walkdir",
+]
+
+[[package]]
name = "ntapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4424,7 +4446,7 @@ dependencies = [
"log4rs",
"miette",
"nix 0.23.1",
- "notify",
+ "notify-debouncer-full",
"once_cell",
"percent-encoding",
"regex",
diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs
index 0e53ce41e..5ae23be4f 100644
--- a/zellij-server/src/plugins/wasm_bridge.rs
+++ b/zellij-server/src/plugins/wasm_bridge.rs
@@ -13,7 +13,7 @@ use std::{
};
use wasmer::{Instance, Module, Store, Value};
use zellij_utils::async_std::task::{self, JoinHandle};
-use zellij_utils::notify::{RecommendedWatcher, Watcher};
+use zellij_utils::notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, FileIdMap};
use crate::{
background_jobs::BackgroundJob, screen::ScreenInstruction, thread_bus::ThreadSenders,
@@ -50,7 +50,7 @@ pub struct WasmBridge {
loading_plugins: HashMap<(PluginId, RunPlugin), JoinHandle<()>>, // plugin_id to join-handle
pending_plugin_reloads: HashSet<RunPlugin>,
path_to_default_shell: PathBuf,
- watcher: Option<RecommendedWatcher>,
+ watcher: Option<Debouncer<RecommendedWatcher, FileIdMap>>,
zellij_cwd: PathBuf,
capabilities: PluginCapabilities,
client_attributes: ClientAttributes,
@@ -530,7 +530,9 @@ impl WasmBridge {
for plugin_id in &plugin_ids {
drop(self.unload_plugin(*plugin_id));
}
- drop(self.watcher.as_mut().map(|w| w.unwatch(&self.zellij_cwd)));
+ if let Some(watcher) = self.watcher.take() {
+ watcher.stop_nonblocking();
+ }
}
fn run_plugin_of_plugin_id(&self, plugin_id: PluginId) -> Option<&RunPlugin> {
self.loading_plugins
diff --git a/zellij-server/src/plugins/watch_filesystem.rs b/zellij-server/src/plugins/watch_filesystem.rs
index 864bd45f9..9ac0a320c 100644
--- a/zellij-server/src/plugins/watch_filesystem.rs
+++ b/zellij-server/src/plugins/watch_filesystem.rs
@@ -3,61 +3,108 @@ use std::path::PathBuf;
use crate::thread_bus::ThreadSenders;
use std::path::Path;
+use std::time::Duration;
-use zellij_utils::{data::Event, errors::prelude::*};
+use zellij_utils::notify_debouncer_full::{
+ new_debouncer,
+ notify::{EventKind, RecommendedWatcher, RecursiveMode, Watcher},
+ DebounceEventResult, Debouncer, FileIdMap,
+};
+use zellij_utils::{data::Event, errors::prelude::Result};
-use zellij_utils::notify::{self, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
-pub fn watch_filesystem(senders: ThreadSenders, zellij_cwd: &Path) -> Result<RecommendedWatcher> {
+const DEBOUNCE_DURATION_MS: u64 = 500;
+
+pub fn watch_filesystem(
+ senders: ThreadSenders,
+ zellij_cwd: &Path,
+) -> Result<Debouncer<RecommendedWatcher, FileIdMap>> {
let path_prefix_in_plugins = PathBuf::from("/host");
let current_dir = PathBuf::from(zellij_cwd);
- let mut watcher = notify::recommended_watcher({
- move |res: notify::Result<notify::Event>| match res {
- Ok(event) => {
- let paths: Vec<PathBuf> = event
- .paths
- .iter()
- .map(|p| {
- let stripped_prefix_path =
- p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
- path_prefix_in_plugins.join(stripped_prefix_path)
+ let mut debouncer = new_debouncer(
+ Duration::from_millis(DEBOUNCE_DURATION_MS),
+ None,
+ move |result: DebounceEventResult| match result {
+ Ok(events) => {
+ let mut create_events = vec![];
+ let mut read_events = vec![];
+ let mut update_events = vec![];
+ let mut delete_events = vec![];
+ for event in events {
+ match event.kind {
+ EventKind::Access(_) => read_events.push(event),
+ EventKind::Create(_) => create_events.push(event),
+ EventKind::Modify(_) => update_events.push(event),
+ EventKind::Remove(_) => delete_events.push(event),
+ _ => {},
+ }
+ }
+ let create_paths: Vec<PathBuf> = create_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
})
.collect();
- match event.kind {
- EventKind::Access(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemRead(paths),
- )]));
- },
- EventKind::Create(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemCreate(paths),
- )]));
- },
- EventKind::Modify(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemUpdate(paths),
- )]));
- },
- EventKind::Remove(_) => {
- let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::FileSystemDelete(paths),
- )]));
- },
- _ => {},
- }
+ let read_paths: Vec<PathBuf> = read_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
+ })
+ .collect();
+ let update_paths: Vec<PathBuf> = update_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
+ })
+ .collect();
+ let delete_paths: Vec<PathBuf> = delete_events
+ .drain(..)
+ .map(|e| {
+ e.paths
+ .iter()
+ .map(|p| {
+ let stripped_prefix_path =
+ p.strip_prefix(&current_dir).unwrap_or_else(|_| p);
+ path_prefix_in_plugins.join(stripped_prefix_path)
+ })
+ .collect()
+ })
+ .collect();
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![
+ (None, None, Event::FileSystemRead(read_paths)),
+ (None, None, Event::FileSystemCreate(create_paths)),
+ (None, None, Event::FileSystemUpdate(update_paths)),
+ (None, None, Event::FileSystemDelete(delete_paths)),
+ ]));
},
- Err(e) => log::error!("watch error: {:?}", e),
- }
- })?;
+ Err(errors) => errors
+ .iter()
+ .for_each(|error| log::error!("watch error: {error:?}")),
+ },
+ )?;
- watcher.watch(zellij_cwd, RecursiveMode::Recursive)?;
- Ok(watcher)
+ debouncer
+ .watcher()
+ .watch(zellij_cwd, RecursiveMode::Recursive)?;
+ Ok(debouncer)
}
diff --git a/zellij-utils/Cargo.toml b/zellij-utils/Cargo.toml
index 2469715f6..cbee7bb86 100644
--- a/zellij-utils/Cargo.toml
+++ b/zellij-utils/Cargo.toml
@@ -40,7 +40,6 @@ tempfile = "3.2.0"
kdl = { version = "4.5.0", features = ["span"] }
shellexpand = "3.0.0"
uuid = { version = "0.8.2", features = ["serde", "v4"] }
-notify = "6.0.0"
async-channel = "1.8.0"
#[cfg(not(target_family = "wasm"))]
@@ -50,6 +49,7 @@ log4rs = "1.2.0"
signal-hook = "0.3"
interprocess = "1.2.1"
async-std = { version = "1.3.0", features = ["unstable"] }
+notify-debouncer-full = "0.1.0"
[dev-dependencies]
insta = { version = "1.6.0", features = ["backtrace"] }
diff --git a/zellij-utils/src/lib.rs b/zellij-utils/src/lib.rs
index 87637de55..b07fe8bdc 100644
--- a/zellij-utils/src/lib.rs
+++ b/zellij-utils/src/lib.rs
@@ -20,6 +20,6 @@ pub mod logging; // Requires log4rs
#[cfg(not(target_family = "wasm"))]
pub use ::{
- anyhow, async_channel, async_std, clap, interprocess, lazy_static, libc, miette, nix, notify,
- regex, serde, signal_hook, tempfile, termwiz, vte,
+ anyhow, async_channel, async_std, clap, interprocess, lazy_static, libc, miette, nix,
+ notify_debouncer_full, regex, serde, signal_hook, tempfile, termwiz, vte,
};