Skip to content

Commit 571ecbf

Browse files
authored
fs: improve error performance of opendirSync
PR-URL: #49705 Refs: nodejs/performance#106 Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent b7d836e commit 571ecbf

File tree

3 files changed

+73
-9
lines changed

3 files changed

+73
-9
lines changed

benchmark/fs/bench-opendirSync.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const tmpdir = require('../../test/common/tmpdir');
7+
tmpdir.refresh();
8+
9+
const testFiles = fs.readdirSync('test', { withFileTypes: true })
10+
.filter((f) => f.isDirectory())
11+
.map((f) => path.join(f.path, f.name));
12+
const bench = common.createBenchmark(main, {
13+
type: ['existing', 'non-existing'],
14+
n: [1e3],
15+
});
16+
17+
function main({ n, type }) {
18+
let files;
19+
20+
switch (type) {
21+
case 'existing':
22+
files = testFiles;
23+
break;
24+
case 'non-existing':
25+
files = [tmpdir.resolve(`.non-existing-file-${Date.now()}`)];
26+
break;
27+
default:
28+
new Error('Invalid type');
29+
}
30+
31+
bench.start();
32+
for (let i = 0; i < n; i++) {
33+
for (let j = 0; j < files.length; j++) {
34+
try {
35+
const dir = fs.opendirSync(files[j]);
36+
dir.closeSync();
37+
} catch {
38+
// do nothing
39+
}
40+
}
41+
}
42+
bench.end(n);
43+
}

lib/internal/fs/dir.js

+2-9
Original file line numberDiff line numberDiff line change
@@ -322,18 +322,11 @@ function opendir(path, options, callback) {
322322

323323
function opendirSync(path, options) {
324324
path = getValidatedPath(path);
325-
options = getOptions(options, {
326-
encoding: 'utf8',
327-
});
325+
options = getOptions(options, { encoding: 'utf8' });
328326

329-
const ctx = { path };
330-
const handle = dirBinding.opendir(
327+
const handle = dirBinding.opendirSync(
331328
pathModule.toNamespacedPath(path),
332-
options.encoding,
333-
undefined,
334-
ctx,
335329
);
336-
handleErrorFromBinding(ctx);
337330

338331
return new Dir(handle, path, options);
339332
}

src/node_dir.cc

+28
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,32 @@ static void OpenDir(const FunctionCallbackInfo<Value>& args) {
397397
}
398398
}
399399

400+
static void OpenDirSync(const FunctionCallbackInfo<Value>& args) {
401+
Environment* env = Environment::GetCurrent(args);
402+
Isolate* isolate = env->isolate();
403+
404+
CHECK_GE(args.Length(), 1);
405+
406+
BufferValue path(isolate, args[0]);
407+
CHECK_NOT_NULL(*path);
408+
THROW_IF_INSUFFICIENT_PERMISSIONS(
409+
env, permission::PermissionScope::kFileSystemRead, path.ToStringView());
410+
411+
uv_fs_t req;
412+
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
413+
FS_DIR_SYNC_TRACE_BEGIN(opendir);
414+
int err = uv_fs_opendir(nullptr, &req, *path, nullptr);
415+
FS_DIR_SYNC_TRACE_END(opendir);
416+
if (err < 0) {
417+
return env->ThrowUVException(err, "opendir");
418+
}
419+
420+
uv_dir_t* dir = static_cast<uv_dir_t*>(req.ptr);
421+
DirHandle* handle = DirHandle::New(env, dir);
422+
423+
args.GetReturnValue().Set(handle->object().As<Value>());
424+
}
425+
400426
void Initialize(Local<Object> target,
401427
Local<Value> unused,
402428
Local<Context> context,
@@ -405,6 +431,7 @@ void Initialize(Local<Object> target,
405431
Isolate* isolate = env->isolate();
406432

407433
SetMethod(context, target, "opendir", OpenDir);
434+
SetMethod(context, target, "opendirSync", OpenDirSync);
408435

409436
// Create FunctionTemplate for DirHandle
410437
Local<FunctionTemplate> dir = NewFunctionTemplate(isolate, DirHandle::New);
@@ -419,6 +446,7 @@ void Initialize(Local<Object> target,
419446

420447
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
421448
registry->Register(OpenDir);
449+
registry->Register(OpenDirSync);
422450
registry->Register(DirHandle::New);
423451
registry->Register(DirHandle::Read);
424452
registry->Register(DirHandle::Close);

0 commit comments

Comments
 (0)