From 5c93aab278f6e09e345270b3a0fe49c591a0424f Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 9 Oct 2019 01:23:18 +0200 Subject: fs: buffer dir entries in opendir() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read up to 32 directory entries in one batch when `dir.readSync()` or `dir.read()` are called. This increases performance significantly, although it introduces quite a bit of edge case complexity. confidence improvement accuracy (*) (**) (***) fs/bench-opendir.js mode='async' dir='lib' n=100 *** 155.93 % ±30.05% ±40.34% ±53.21% fs/bench-opendir.js mode='async' dir='test/parallel' n=100 *** 479.65 % ±56.81% ±76.47% ±101.32% fs/bench-opendir.js mode='sync' dir='lib' n=100 10.38 % ±14.39% ±19.16% ±24.96% fs/bench-opendir.js mode='sync' dir='test/parallel' n=100 *** 63.13 % ±12.84% ±17.18% ±22.58% PR-URL: https://github.com/nodejs/node/pull/29893 Reviewed-By: Colin Ihrig Reviewed-By: David Carlier Reviewed-By: James M Snell Reviewed-By: Jeremiah Senkpiel --- lib/internal/fs/dir.js | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/internal/fs/dir.js b/lib/internal/fs/dir.js index 175c632fc7..fedd7ff8ed 100644 --- a/lib/internal/fs/dir.js +++ b/lib/internal/fs/dir.js @@ -24,8 +24,10 @@ const { const kDirHandle = Symbol('kDirHandle'); const kDirPath = Symbol('kDirPath'); +const kDirBufferedEntries = Symbol('kDirBufferedEntries'); const kDirClosed = Symbol('kDirClosed'); const kDirOptions = Symbol('kDirOptions'); +const kDirReadImpl = Symbol('kDirReadImpl'); const kDirReadPromisified = Symbol('kDirReadPromisified'); const kDirClosePromisified = Symbol('kDirClosePromisified'); @@ -33,6 +35,7 @@ class Dir { constructor(handle, path, options) { if (handle == null) throw new ERR_MISSING_ARGS('handle'); this[kDirHandle] = handle; + this[kDirBufferedEntries] = []; this[kDirPath] = path; this[kDirClosed] = false; @@ -40,7 +43,8 @@ class Dir { encoding: 'utf8' }); - this[kDirReadPromisified] = internalUtil.promisify(this.read).bind(this); + this[kDirReadPromisified] = + internalUtil.promisify(this[kDirReadImpl]).bind(this, false); this[kDirClosePromisified] = internalUtil.promisify(this.close).bind(this); } @@ -49,6 +53,10 @@ class Dir { } read(callback) { + return this[kDirReadImpl](true, callback); + } + + [kDirReadImpl](maybeSync, callback) { if (this[kDirClosed] === true) { throw new ERR_DIR_CLOSED(); } @@ -59,11 +67,22 @@ class Dir { throw new ERR_INVALID_CALLBACK(callback); } + if (this[kDirBufferedEntries].length > 0) { + const [ name, type ] = this[kDirBufferedEntries].splice(0, 2); + if (maybeSync) + process.nextTick(getDirent, this[kDirPath], name, type, callback); + else + getDirent(this[kDirPath], name, type, callback); + return; + } + const req = new FSReqCallback(); req.oncomplete = (err, result) => { if (err || result === null) { return callback(err, result); } + + this[kDirBufferedEntries] = result.slice(2); getDirent(this[kDirPath], result[0], result[1], callback); }; @@ -78,6 +97,11 @@ class Dir { throw new ERR_DIR_CLOSED(); } + if (this[kDirBufferedEntries].length > 0) { + const [ name, type ] = this[kDirBufferedEntries].splice(0, 2); + return getDirent(this[kDirPath], name, type); + } + const ctx = { path: this[kDirPath] }; const result = this[kDirHandle].read( this[kDirOptions].encoding, @@ -90,6 +114,7 @@ class Dir { return result; } + this[kDirBufferedEntries] = result.slice(2); return getDirent(this[kDirPath], result[0], result[1]); } -- cgit v1.2.3