Skip to content

Commit 8d0edc6

Browse files
CanadaHonktargos
authored andcommitted
fs: improve error performance for mkdirSync
PR-URL: #49847 Refs: nodejs/performance#106 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent c37a75a commit 8d0edc6

File tree

4 files changed

+68
-40
lines changed

4 files changed

+68
-40
lines changed

benchmark/fs/bench-mkdirSync.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fs = require('fs');
5+
const tmpdir = require('../../test/common/tmpdir');
6+
tmpdir.refresh();
7+
8+
const bench = common.createBenchmark(main, {
9+
type: ['existing', 'non-existing'],
10+
recursive: ['true', 'false'],
11+
n: [1e3],
12+
});
13+
14+
function main({ n, type, recursive }) {
15+
recursive = recursive === 'true';
16+
let files;
17+
18+
switch (type) {
19+
case 'non-existing':
20+
files = [];
21+
22+
// Populate tmpdir with target dirs
23+
for (let i = 0; i < n; i++) {
24+
const path = tmpdir.resolve(recursive ? `rmdirsync-bench-dir-${process.pid}-${i}/a/b/c` : `rmdirsync-bench-dir-${process.pid}-${i}`);
25+
files.push(path);
26+
}
27+
break;
28+
case 'existing':
29+
files = new Array(n).fill(__dirname);
30+
break;
31+
default:
32+
new Error('Invalid type');
33+
}
34+
35+
bench.start();
36+
for (let i = 0; i < n; i++) {
37+
try {
38+
fs.mkdirSync(files[i], { recursive });
39+
} catch {
40+
// do nothing
41+
}
42+
}
43+
bench.end(n);
44+
}

lib/fs.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -1383,11 +1383,12 @@ function mkdirSync(path, options) {
13831383
path = getValidatedPath(path);
13841384
validateBoolean(recursive, 'options.recursive');
13851385

1386-
const ctx = { path };
1387-
const result = binding.mkdir(pathModule.toNamespacedPath(path),
1388-
parseFileMode(mode, 'mode'), recursive,
1389-
undefined, ctx);
1390-
handleErrorFromBinding(ctx);
1386+
const result = binding.mkdir(
1387+
pathModule.toNamespacedPath(path),
1388+
parseFileMode(mode, 'mode'),
1389+
recursive,
1390+
);
1391+
13911392
if (recursive) {
13921393
return result;
13931394
}

src/node_file.cc

+15-32
Original file line numberDiff line numberDiff line change
@@ -1786,30 +1786,11 @@ int MKDirpAsync(uv_loop_t* loop,
17861786
return err;
17871787
}
17881788

1789-
int CallMKDirpSync(Environment* env, const FunctionCallbackInfo<Value>& args,
1790-
FSReqWrapSync* req_wrap, const char* path, int mode) {
1791-
env->PrintSyncTrace();
1792-
int err = MKDirpSync(env->event_loop(), &req_wrap->req, path, mode,
1793-
nullptr);
1794-
if (err < 0) {
1795-
v8::Local<v8::Context> context = env->context();
1796-
v8::Local<v8::Object> ctx_obj = args[4].As<v8::Object>();
1797-
v8::Isolate* isolate = env->isolate();
1798-
ctx_obj->Set(context,
1799-
env->errno_string(),
1800-
v8::Integer::New(isolate, err)).Check();
1801-
ctx_obj->Set(context,
1802-
env->syscall_string(),
1803-
OneByteString(isolate, "mkdir")).Check();
1804-
}
1805-
return err;
1806-
}
1807-
18081789
static void MKDir(const FunctionCallbackInfo<Value>& args) {
18091790
Environment* env = Environment::GetCurrent(args);
18101791

18111792
const int argc = args.Length();
1812-
CHECK_GE(argc, 4);
1793+
CHECK_GE(argc, 3);
18131794

18141795
BufferValue path(env->isolate(), args[0]);
18151796
CHECK_NOT_NULL(*path);
@@ -1822,37 +1803,39 @@ static void MKDir(const FunctionCallbackInfo<Value>& args) {
18221803
CHECK(args[2]->IsBoolean());
18231804
bool mkdirp = args[2]->IsTrue();
18241805

1825-
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
1826-
if (req_wrap_async != nullptr) { // mkdir(path, mode, req)
1806+
if (argc > 3) { // mkdir(path, mode, recursive, req)
1807+
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
18271808
FS_ASYNC_TRACE_BEGIN1(
18281809
UV_FS_UNLINK, req_wrap_async, "path", TRACE_STR_COPY(*path))
18291810
AsyncCall(env, req_wrap_async, args, "mkdir", UTF8,
18301811
mkdirp ? AfterMkdirp : AfterNoArgs,
18311812
mkdirp ? MKDirpAsync : uv_fs_mkdir, *path, mode);
1832-
} else { // mkdir(path, mode, undefined, ctx)
1833-
CHECK_EQ(argc, 5);
1834-
FSReqWrapSync req_wrap_sync;
1813+
} else { // mkdir(path, mode, recursive)
1814+
FSReqWrapSync req_wrap_sync("mkdir", *path);
18351815
FS_SYNC_TRACE_BEGIN(mkdir);
18361816
if (mkdirp) {
1837-
int err = CallMKDirpSync(env, args, &req_wrap_sync, *path, mode);
1838-
if (err == 0 &&
1839-
!req_wrap_sync.continuation_data()->first_path().empty()) {
1817+
env->PrintSyncTrace();
1818+
int err = MKDirpSync(
1819+
env->event_loop(), &req_wrap_sync.req, *path, mode, nullptr);
1820+
if (is_uv_error(err)) {
1821+
env->ThrowUVException(err, "mkdir", nullptr, *path);
1822+
return;
1823+
}
1824+
if (!req_wrap_sync.continuation_data()->first_path().empty()) {
18401825
Local<Value> error;
18411826
std::string first_path(req_wrap_sync.continuation_data()->first_path());
18421827
FromNamespacedPath(&first_path);
18431828
MaybeLocal<Value> path = StringBytes::Encode(env->isolate(),
18441829
first_path.c_str(),
18451830
UTF8, &error);
18461831
if (path.IsEmpty()) {
1847-
Local<Object> ctx = args[4].As<Object>();
1848-
ctx->Set(env->context(), env->error_string(), error).Check();
1832+
env->isolate()->ThrowException(error);
18491833
return;
18501834
}
18511835
args.GetReturnValue().Set(path.ToLocalChecked());
18521836
}
18531837
} else {
1854-
SyncCall(env, args[4], &req_wrap_sync, "mkdir",
1855-
uv_fs_mkdir, *path, mode);
1838+
SyncCallAndThrowOnError(env, &req_wrap_sync, uv_fs_mkdir, *path, mode);
18561839
}
18571840
FS_SYNC_TRACE_END(mkdir);
18581841
}

typings/internalBinding/fs.d.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,9 @@ declare namespace InternalFSBinding {
146146
function mkdir(path: string, mode: number, recursive: boolean, req: FSReqCallback<void | string>): void;
147147
function mkdir(path: string, mode: number, recursive: true, req: FSReqCallback<string>): void;
148148
function mkdir(path: string, mode: number, recursive: false, req: FSReqCallback<void>): void;
149-
function mkdir(path: string, mode: number, recursive: boolean, req: undefined, ctx: FSSyncContext): void | string;
150-
function mkdir(path: string, mode: number, recursive: true, req: undefined, ctx: FSSyncContext): string;
151-
function mkdir(path: string, mode: number, recursive: false, req: undefined, ctx: FSSyncContext): void;
149+
function mkdir(path: string, mode: number, recursive: boolean): void | string;
150+
function mkdir(path: string, mode: number, recursive: true): string;
151+
function mkdir(path: string, mode: number, recursive: false): void;
152152
function mkdir(path: string, mode: number, recursive: boolean, usePromises: typeof kUsePromises): Promise<void | string>;
153153
function mkdir(path: string, mode: number, recursive: true, usePromises: typeof kUsePromises): Promise<string>;
154154
function mkdir(path: string, mode: number, recursive: false, usePromises: typeof kUsePromises): Promise<void>;

0 commit comments

Comments
 (0)