From c29734c9d64c79ee38b6d462bf356b32c8dd80b7 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 17 Jul 2018 03:05:04 +0200 Subject: [PATCH] fs: improve fs.watch ENOSPC error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Providing `No space left on device` is misleading in this case. Replace it with something that describes it more accurately. Refs: https://stackoverflow.com/questions/22475849/node-js-error-enospc/32600959 PR-URL: https://github.com/nodejs/node/pull/21846 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Michaƫl Zasso Reviewed-By: Ruben Bridgewater Reviewed-By: Sakthipriyan Vairamani --- lib/internal/errors.js | 2 +- lib/internal/fs/watchers.js | 5 +- test/sequential/test-fs-watch-system-limit.js | 51 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 test/sequential/test-fs-watch-system-limit.js diff --git a/lib/internal/errors.js b/lib/internal/errors.js index cfc1a9bcc9ea59..4fc43f1a6cbe7e 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -249,7 +249,7 @@ function getMessage(key, args) { */ function uvException(ctx) { const [ code, uvmsg ] = errmap.get(ctx.errno); - let message = `${code}: ${uvmsg}, ${ctx.syscall}`; + let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`; let path; let dest; diff --git a/lib/internal/fs/watchers.js b/lib/internal/fs/watchers.js index 90ea3971aae6f5..679f5c9d834be4 100644 --- a/lib/internal/fs/watchers.js +++ b/lib/internal/fs/watchers.js @@ -6,6 +6,7 @@ const { StatWatcher: _StatWatcher } = process.binding('fs'); const { FSEvent } = process.binding('fs_event_wrap'); +const { UV_ENOSPC } = process.binding('uv'); const { EventEmitter } = require('events'); const { getStatsFromBinding, @@ -164,7 +165,9 @@ FSWatcher.prototype.start = function(filename, const error = errors.uvException({ errno: err, syscall: 'watch', - path: filename + path: filename, + message: err === UV_ENOSPC ? + 'System limit for number of file watchers reached' : '' }); error.filename = filename; throw error; diff --git a/test/sequential/test-fs-watch-system-limit.js b/test/sequential/test-fs-watch-system-limit.js new file mode 100644 index 00000000000000..f7af3be86c29f4 --- /dev/null +++ b/test/sequential/test-fs-watch-system-limit.js @@ -0,0 +1,51 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); +const stream = require('stream'); + +if (!common.isLinux) + common.skip('The fs watch limit is OS-dependent'); +if (!common.enoughTestCpu) + common.skip('This test is resource-intensive'); + +const processes = []; +const gatherStderr = new stream.PassThrough(); +gatherStderr.setEncoding('utf8'); +gatherStderr.setMaxListeners(Infinity); + +let finished = false; +function spawnProcesses() { + for (let i = 0; i < 10; ++i) { + const proc = child_process.spawn( + process.execPath, + [ '-e', + `process.chdir(${JSON.stringify(__dirname)}); + for (const file of fs.readdirSync('.')) + fs.watch(file, () => {});` + ], { stdio: ['inherit', 'inherit', 'pipe'] }); + proc.stderr.pipe(gatherStderr); + processes.push(proc); + } + + setTimeout(() => { + if (!finished && processes.length < 200) + spawnProcesses(); + }, 100); +} + +spawnProcesses(); + +let accumulated = ''; +gatherStderr.on('data', common.mustCallAtLeast((chunk) => { + accumulated += chunk; + if (accumulated.includes('Error:') && !finished) { + assert( + accumulated.includes('ENOSPC: System limit for number ' + + 'of file watchers reached'), + accumulated); + console.log(`done after ${processes.length} processes, cleaning up`); + finished = true; + processes.forEach((proc) => proc.kill()); + } +}, 1));