From a2d0a251da02f424ee94b25acbdb22d8de047704 Mon Sep 17 00:00:00 2001 From: Paul Colomiets Date: Wed, 1 Aug 2018 18:36:19 +0300 Subject: [PATCH] Add a warning and fallback on polling mode if limit exceeded Works only on linux (not sure how error is named on other systems): ``` *** System notification limit is too small, falling back to polling mode. *** For better performance increase system limit: sysctl fs.inotify.max_user_watches=524288 *** Polling for changes every 1000 ms ``` Fixes #62 --- src/run.rs | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/run.rs b/src/run.rs index 0128301..6109407 100644 --- a/src/run.rs +++ b/src/run.rs @@ -8,6 +8,7 @@ use cli; use env_logger; use gitignore; use log; +use notify::Error; use notification_filter::NotificationFilter; use process::{self, Process}; use signal::{self, Signal}; @@ -28,6 +29,22 @@ fn init_logger(debug: bool) { log_builder.init().expect("unable to initialize logger"); } +#[cfg(target_os="linux")] +fn should_switch_to_poll(e: &Error) -> bool { + use nix::libc; + + match e { + &Error::Io(ref e) if e.raw_os_error() == Some(libc::ENOSPC) => true, + _ => false, + } +} + +#[cfg(not(target_os="linux"))] +fn should_switch_to_poll(_: &Error) -> bool { + // not known conditions to switch + false +} + pub fn run(args: cli::Args) { let child_process: Arc>> = Arc::new(RwLock::new(None)); let weak_child = Arc::downgrade(&child_process); @@ -69,8 +86,22 @@ pub fn run(args: cli::Args) { .expect("unable to create notification filter"); let (tx, rx) = channel(); - let watcher = - Watcher::new(tx, &paths, args.poll, args.poll_interval).expect("unable to create watcher"); + let watcher = match Watcher::new(tx.clone(), &paths, args.poll, args.poll_interval) { + Ok(watcher) => watcher, + Err(ref e) if !args.poll && should_switch_to_poll(e) => { + warn!("System notification limit is too small, \ + falling back to polling mode."); + if cfg!(target_os="linux") { + warn!("For better performance increase system limit: \n \ + sysctl fs.inotify.max_user_watches=524288"); + } + Watcher::new(tx, &paths, true, args.poll_interval) + .expect("polling watcher should always work") + } + Err(e) => { + panic!("Error setting up watcher: {}", e); + } + }; if watcher.is_polling() { warn!("Polling for changes every {} ms", args.poll_interval);