diff --git a/lib/fsevents-handler.js b/lib/fsevents-handler.js index 94297537..a86bc1f0 100644 --- a/lib/fsevents-handler.js +++ b/lib/fsevents-handler.js @@ -12,6 +12,10 @@ try { fsevents = require('fsevents'); } catch (error) {} // (may be shared across chokidar FSWatcher instances) var FSEventsWatchers = Object.create(null); +// Threshold of duplicate path prefixes at which to start +// consolidating going forward +var consolidateThreshhold = 10; + // Private function: Instantiates the fsevents interface // * path - string, path to be watched @@ -34,6 +38,15 @@ function createFSEventsInstance(path, callback) { function setFSEventsListener(path, realPath, listener, rawEmitter) { var watchPath = sysPath.extname(path) ? sysPath.dirname(path) : path; var watchContainer; + var parentPath = sysPath.dirname(watchPath); + + // If we've accumulated a substantial number of paths that + // could have been consolidated by watching one directory + // above the current one, create a watcher on the parent + // path instead, so that we do consolidate going forward. + if (couldConsolidate(parentPath)) { + watchPath = parentPath; + } var resolvedPath = sysPath.resolve(path); var hasSymlink = resolvedPath !== realPath; @@ -89,6 +102,25 @@ function setFSEventsListener(path, realPath, listener, rawEmitter) { }; } +// Decide whether or not we should start a new higher-level +// parent watcher +function couldConsolidate(path) { + var keys = Object.keys(FSEventsWatchers); + var count = 0; + + for (var i = 0, len = keys.length; i < len; ++i) { + var watchPath = keys[i]; + if (watchPath.indexOf(path) === 0) { + count++; + if (count >= consolidateThreshhold) { + return true; + } + } + } + + return false; +} + // returns boolean indicating whether fsevents can be used function canUse() { return fsevents && Object.keys(FSEventsWatchers).length < 128;