| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e4ab6fc commit 07b5584
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,22 +7,24 @@ const path = require('path'); | |||
| 7 | 7 | const bench = common.createBenchmark(main, { | |
| 8 | 8 | n: [100], | |
| 9 | 9 | dir: [ 'lib', 'test/parallel'], | |
| 10 | - mode: [ 'async', 'sync', 'callback' ] | ||
| 10 | + mode: [ 'async', 'sync', 'callback' ], | ||
| 11 | + bufferSize: [ 4, 32, 1024 ] | ||
| 11 | 12 | }); | |
| 12 | 13 | ||
| 13 | - async function main({ n, dir, mode }) { | ||
| 14 | + async function main({ n, dir, mode, bufferSize }) { | ||
| 14 | 15 | const fullPath = path.resolve(__dirname, '../../', dir); | |
| 15 | 16 | ||
| 16 | 17 | bench.start(); | |
| 17 | 18 | ||
| 18 | 19 | let counter = 0; | |
| 19 | 20 | for (let i = 0; i < n; i++) { | |
| 20 | 21 | if (mode === 'async') { | |
| 22 | + const dir = await fs.promises.opendir(fullPath, { bufferSize }); | ||
| 21 | 23 | // eslint-disable-next-line no-unused-vars | |
| 22 | - for await (const entry of await fs.promises.opendir(fullPath)) | ||
| 24 | + for await (const entry of dir) | ||
| 23 | 25 | counter++; | |
| 24 | 26 | } else if (mode === 'callback') { | |
| 25 | - const dir = await fs.promises.opendir(fullPath); | ||
| 27 | + const dir = await fs.promises.opendir(fullPath, { bufferSize }); | ||
| 26 | 28 | await new Promise((resolve, reject) => { | |
| 27 | 29 | function read() { | |
| 28 | 30 | dir.read((err, entry) => { | |
@@ -40,7 +42,7 @@ async function main({ n, dir, mode }) { | |||
| 40 | 42 | read(); | |
| 41 | 43 | }); | |
| 42 | 44 | } else { | |
| 43 | - const dir = fs.opendirSync(fullPath); | ||
| 45 | + const dir = fs.opendirSync(fullPath, { bufferSize }); | ||
| 44 | 46 | while (dir.readSync() !== null) | |
| 45 | 47 | counter++; | |
| 46 | 48 | dir.closeSync(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2625,11 +2625,18 @@ Functions based on `fs.open()` exhibit this behavior as well: | |||
| 2625 | 2625 | ## fs.opendir(path\[, options\], callback) | |
| 2626 | 2626 | <!-- YAML | |
| 2627 | 2627 | added: v12.12.0 | |
| 2628 | + changes: | ||
| 2629 | + - version: REPLACEME | ||
| 2630 | + pr-url: https://github.com/nodejs/node/pull/30114 | ||
| 2631 | + description: The `bufferSize` option was introduced. | ||
| 2628 | 2632 | --> | |
| 2629 | 2633 | ||
| 2630 | 2634 | * `path` {string|Buffer|URL} | |
| 2631 | 2635 | * `options` {Object} | |
| 2632 | 2636 | * `encoding` {string|null} **Default:** `'utf8'` | |
| 2637 | + * `bufferSize` {number} Number of directory entries that are buffered | ||
| 2638 | + internally when reading from the directory. Higher values lead to better | ||
| 2639 | + performance but higher memory usage. **Default:** `32` | ||
| 2633 | 2640 | * `callback` {Function} | |
| 2634 | 2641 | * `err` {Error} | |
| 2635 | 2642 | * `dir` {fs.Dir} | |
@@ -2645,11 +2652,18 @@ directory and subsequent read operations. | |||
| 2645 | 2652 | ## fs.opendirSync(path\[, options\]) | |
| 2646 | 2653 | <!-- YAML | |
| 2647 | 2654 | added: v12.12.0 | |
| 2655 | + changes: | ||
| 2656 | + - version: REPLACEME | ||
| 2657 | + pr-url: https://github.com/nodejs/node/pull/30114 | ||
| 2658 | + description: The `bufferSize` option was introduced. | ||
| 2648 | 2659 | --> | |
| 2649 | 2660 | ||
| 2650 | 2661 | * `path` {string|Buffer|URL} | |
| 2651 | 2662 | * `options` {Object} | |
| 2652 | 2663 | * `encoding` {string|null} **Default:** `'utf8'` | |
| 2664 | + * `bufferSize` {number} Number of directory entries that are buffered | ||
| 2665 | + internally when reading from the directory. Higher values lead to better | ||
| 2666 | + performance but higher memory usage. **Default:** `32` | ||
| 2653 | 2667 | * Returns: {fs.Dir} | |
| 2654 | 2668 | ||
| 2655 | 2669 | Synchronously open a directory. See opendir(3). | |
@@ -4829,11 +4843,18 @@ a colon, Node.js will open a file system stream, as described by | |||
| 4829 | 4843 | ### fsPromises.opendir(path\[, options\]) | |
| 4830 | 4844 | <!-- YAML | |
| 4831 | 4845 | added: v12.12.0 | |
| 4846 | + changes: | ||
| 4847 | + - version: REPLACEME | ||
| 4848 | + pr-url: https://github.com/nodejs/node/pull/30114 | ||
| 4849 | + description: The `bufferSize` option was introduced. | ||
| 4832 | 4850 | --> | |
| 4833 | 4851 | ||
| 4834 | 4852 | * `path` {string|Buffer|URL} | |
| 4835 | 4853 | * `options` {Object} | |
| 4836 | 4854 | * `encoding` {string|null} **Default:** `'utf8'` | |
| 4855 | + * `bufferSize` {number} Number of directory entries that are buffered | ||
| 4856 | + internally when reading from the directory. Higher values lead to better | ||
| 4857 | + performance but higher memory usage. **Default:** `32` | ||
| 4837 | 4858 | * Returns: {Promise} containing {fs.Dir} | |
| 4838 | 4859 | ||
| 4839 | 4860 | Asynchronously open a directory. See opendir(3). | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,6 +21,9 @@ const { | |||
| 21 | 21 | getValidatedPath, | |
| 22 | 22 | handleErrorFromBinding | |
| 23 | 23 | } = require('internal/fs/utils'); | |
| 24 | + const { | ||
| 25 | + validateUint32 | ||
| 26 | + } = require('internal/validators'); | ||
| 24 | 27 | ||
| 25 | 28 | const kDirHandle = Symbol('kDirHandle'); | |
| 26 | 29 | const kDirPath = Symbol('kDirPath'); | |
@@ -39,9 +42,14 @@ class Dir { | |||
| 39 | 42 | this[kDirPath] = path; | |
| 40 | 43 | this[kDirClosed] = false; | |
| 41 | 44 | ||
| 42 | - this[kDirOptions] = getOptions(options, { | ||
| 43 | - encoding: 'utf8' | ||
| 44 | - }); | ||
| 45 | + this[kDirOptions] = { | ||
| 46 | + bufferSize: 32, | ||
| 47 | + ...getOptions(options, { | ||
| 48 | + encoding: 'utf8' | ||
| 49 | + }) | ||
| 50 | + }; | ||
| 51 | + | ||
| 52 | + validateUint32(this[kDirOptions].bufferSize, 'options.bufferSize', true); | ||
| 45 | 53 | ||
| 46 | 54 | this[kDirReadPromisified] = | |
| 47 | 55 | internalUtil.promisify(this[kDirReadImpl]).bind(this, false); | |
@@ -88,6 +96,7 @@ class Dir { | |||
| 88 | 96 | ||
| 89 | 97 | this[kDirHandle].read( | |
| 90 | 98 | this[kDirOptions].encoding, | |
| 99 | + this[kDirOptions].bufferSize, | ||
| 91 | 100 | req | |
| 92 | 101 | ); | |
| 93 | 102 | } | |
@@ -105,6 +114,7 @@ class Dir { | |||
| 105 | 114 | const ctx = { path: this[kDirPath] }; | |
| 106 | 115 | const result = this[kDirHandle].read( | |
| 107 | 116 | this[kDirOptions].encoding, | |
| 117 | + this[kDirOptions].bufferSize, | ||
| 108 | 118 | undefined, | |
| 109 | 119 | ctx | |
| 110 | 120 | ); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -36,6 +36,7 @@ using v8::Isolate; | |||
| 36 | 36 | using v8::Local; | |
| 37 | 37 | using v8::MaybeLocal; | |
| 38 | 38 | using v8::Null; | |
| 39 | + using v8::Number; | ||
| 39 | 40 | using v8::Object; | |
| 40 | 41 | using v8::ObjectTemplate; | |
| 41 | 42 | using v8::String; | |
@@ -59,8 +60,8 @@ DirHandle::DirHandle(Environment* env, Local<Object> obj, uv_dir_t* dir) | |||
| 59 | 60 | dir_(dir) { | |
| 60 | 61 | MakeWeak(); | |
| 61 | 62 | ||
| 62 | - dir_->nentries = arraysize(dirents_); | ||
| 63 | - dir_->dirents = dirents_; | ||
| 63 | + dir_->nentries = 0; | ||
| 64 | + dir_->dirents = nullptr; | ||
| 64 | 65 | } | |
| 65 | 66 | ||
| 66 | 67 | DirHandle* DirHandle::New(Environment* env, uv_dir_t* dir) { | |
@@ -230,22 +231,31 @@ void DirHandle::Read(const FunctionCallbackInfo<Value>& args) { | |||
| 230 | 231 | Isolate* isolate = env->isolate(); | |
| 231 | 232 | ||
| 232 | 233 | const int argc = args.Length(); | |
| 233 | - CHECK_GE(argc, 2); | ||
| 234 | + CHECK_GE(argc, 3); | ||
| 234 | 235 | ||
| 235 | 236 | const enum encoding encoding = ParseEncoding(isolate, args[0], UTF8); | |
| 236 | 237 | ||
| 237 | 238 | DirHandle* dir; | |
| 238 | 239 | ASSIGN_OR_RETURN_UNWRAP(&dir, args.Holder()); | |
| 239 | 240 | ||
| 240 | - FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); | ||
| 241 | - if (req_wrap_async != nullptr) { // dir.read(encoding, req) | ||
| 241 | + CHECK(args[1]->IsNumber()); | ||
| 242 | + uint64_t buffer_size = args[1].As<Number>()->Value(); | ||
| 243 | + | ||
| 244 | + if (buffer_size != dir->dirents_.size()) { | ||
| 245 | + dir->dirents_.resize(buffer_size); | ||
| 246 | + dir->dir_->nentries = buffer_size; | ||
| 247 | + dir->dir_->dirents = dir->dirents_.data(); | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); | ||
| 251 | + if (req_wrap_async != nullptr) { // dir.read(encoding, bufferSize, req) | ||
| 242 | 252 | AsyncCall(env, req_wrap_async, args, "readdir", encoding, | |
| 243 | 253 | AfterDirRead, uv_fs_readdir, dir->dir()); | |
| 244 | - } else { // dir.read(encoding, undefined, ctx) | ||
| 245 | - CHECK_EQ(argc, 3); | ||
| 254 | + } else { // dir.read(encoding, bufferSize, undefined, ctx) | ||
| 255 | + CHECK_EQ(argc, 4); | ||
| 246 | 256 | FSReqWrapSync req_wrap_sync; | |
| 247 | 257 | FS_DIR_SYNC_TRACE_BEGIN(readdir); | |
| 248 | - int err = SyncCall(env, args[2], &req_wrap_sync, "readdir", uv_fs_readdir, | ||
| 258 | + int err = SyncCall(env, args[3], &req_wrap_sync, "readdir", uv_fs_readdir, | ||
| 249 | 259 | dir->dir()); | |
| 250 | 260 | FS_DIR_SYNC_TRACE_END(readdir); | |
| 251 | 261 | if (err < 0) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,8 +45,8 @@ class DirHandle : public AsyncWrap { | |||
| 45 | 45 | void GCClose(); | |
| 46 | 46 | ||
| 47 | 47 | uv_dir_t* dir_; | |
| 48 | - // Up to 32 directory entries are read through a single libuv call. | ||
| 49 | - uv_dirent_t dirents_[32]; | ||
| 48 | + // Multiple entries are read through a single libuv call. | ||
| 49 | + std::vector<uv_dirent_t> dirents_; | ||
| 50 | 50 | bool closing_ = false; | |
| 51 | 51 | bool closed_ = false; | |
| 52 | 52 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,6 +7,7 @@ const tmpdir = require('../common/tmpdir'); | |||
| 7 | 7 | tmpdir.refresh(); | |
| 8 | 8 | ||
| 9 | 9 | runBenchmark('fs', [ | |
| 10 | + 'bufferSize=32', | ||
| 10 | 11 | 'concurrent=1', | |
| 11 | 12 | 'dir=.github', | |
| 12 | 13 | 'dur=0.1', | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -182,3 +182,26 @@ async function doAsyncIterThrowTest() { | |||
| 182 | 182 | await assert.rejects(async () => dir.read(), dirclosedError); | |
| 183 | 183 | } | |
| 184 | 184 | doAsyncIterThrowTest().then(common.mustCall()); | |
| 185 | + | ||
| 186 | + // Check error thrown on invalid values of bufferSize | ||
| 187 | + for (const bufferSize of [-1, 0, 0.5, 1.5, Infinity, NaN]) { | ||
| 188 | + assert.throws( | ||
| 189 | + () => fs.opendirSync(testDir, { bufferSize }), | ||
| 190 | + { | ||
| 191 | + code: 'ERR_OUT_OF_RANGE' | ||
| 192 | + }); | ||
| 193 | + } | ||
| 194 | + for (const bufferSize of ['', '1', null]) { | ||
| 195 | + assert.throws( | ||
| 196 | + () => fs.opendirSync(testDir, { bufferSize }), | ||
| 197 | + { | ||
| 198 | + code: 'ERR_INVALID_ARG_TYPE' | ||
| 199 | + }); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + // Check that passing a positive integer as bufferSize works | ||
| 203 | + { | ||
| 204 | + const dir = fs.opendirSync(testDir, { bufferSize: 1024 }); | ||
| 205 | + assertDirent(dir.readSync()); | ||
| 206 | + dir.close(); | ||
| 207 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments