Skip to content

Commit 6bc7fa7

Browse files
CanadaHonkanonrig
authored andcommitted
fs: improve error perf of sync chmod+fchmod
PR-URL: #49859 Refs: nodejs/performance#106 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Darshan Sen <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 6bd77db commit 6bc7fa7

File tree

5 files changed

+121
-24
lines changed

5 files changed

+121
-24
lines changed

benchmark/fs/bench-chmodSync.js

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
n: [1e3],
11+
});
12+
13+
function main({ n, type }) {
14+
switch (type) {
15+
case 'existing': {
16+
for (let i = 0; i < n; i++) {
17+
fs.writeFileSync(tmpdir.resolve(`chmodsync-bench-file-${i}`), 'bench');
18+
}
19+
20+
bench.start();
21+
for (let i = 0; i < n; i++) {
22+
fs.chmodSync(tmpdir.resolve(`chmodsync-bench-file-${i}`), 0o666);
23+
}
24+
bench.end(n);
25+
break;
26+
}
27+
case 'non-existing':
28+
bench.start();
29+
for (let i = 0; i < n; i++) {
30+
try {
31+
fs.chmodSync(tmpdir.resolve(`chmod-non-existing-file-${i}`), 0o666);
32+
} catch {
33+
// do nothing
34+
}
35+
}
36+
bench.end(n);
37+
break;
38+
default:
39+
new Error('Invalid type');
40+
}
41+
}

benchmark/fs/bench-fchmodSync.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
n: [1e3],
11+
});
12+
13+
function main({ n, type }) {
14+
let files;
15+
16+
switch (type) {
17+
case 'existing':
18+
files = [];
19+
20+
// Populate tmpdir with mock files
21+
for (let i = 0; i < n; i++) {
22+
const path = tmpdir.resolve(`fchmodsync-bench-file-${i}`);
23+
fs.writeFileSync(path, 'bench');
24+
files.push(path);
25+
}
26+
break;
27+
case 'non-existing':
28+
files = new Array(n).fill(tmpdir.resolve(`.non-existing-file-${Date.now()}`));
29+
break;
30+
default:
31+
new Error('Invalid type');
32+
}
33+
34+
const fds = files.map((x) => {
35+
// Try to open, if not return likely invalid fd (1 << 30)
36+
try {
37+
return fs.openSync(x, 'r');
38+
} catch {
39+
return 1 << 30;
40+
}
41+
});
42+
43+
bench.start();
44+
for (let i = 0; i < n; i++) {
45+
try {
46+
fs.fchmodSync(fds[i], 0o666);
47+
} catch {
48+
// do nothing
49+
}
50+
}
51+
bench.end(n);
52+
53+
for (const x of fds) {
54+
try {
55+
fs.closeSync(x);
56+
} catch {
57+
// do nothing
58+
}
59+
}
60+
}

lib/fs.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -1903,11 +1903,10 @@ function fchmod(fd, mode, callback) {
19031903
* @returns {void}
19041904
*/
19051905
function fchmodSync(fd, mode) {
1906-
fd = getValidatedFd(fd);
1907-
mode = parseFileMode(mode, 'mode');
1908-
const ctx = {};
1909-
binding.fchmod(fd, mode, undefined, ctx);
1910-
handleErrorFromBinding(ctx);
1906+
binding.fchmod(
1907+
getValidatedFd(fd),
1908+
parseFileMode(mode, 'mode'),
1909+
);
19111910
}
19121911

19131912
/**
@@ -1982,9 +1981,10 @@ function chmodSync(path, mode) {
19821981
path = getValidatedPath(path);
19831982
mode = parseFileMode(mode, 'mode');
19841983

1985-
const ctx = { path };
1986-
binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx);
1987-
handleErrorFromBinding(ctx);
1984+
binding.chmod(
1985+
pathModule.toNamespacedPath(path),
1986+
mode,
1987+
);
19881988
}
19891989

19901990
/**

src/node_file.cc

+10-14
Original file line numberDiff line numberDiff line change
@@ -2517,18 +2517,16 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) {
25172517
CHECK(args[1]->IsInt32());
25182518
int mode = args[1].As<Int32>()->Value();
25192519

2520-
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2521-
if (req_wrap_async != nullptr) { // chmod(path, mode, req)
2520+
if (argc > 2) { // chmod(path, mode, req)
2521+
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
25222522
FS_ASYNC_TRACE_BEGIN1(
25232523
UV_FS_CHMOD, req_wrap_async, "path", TRACE_STR_COPY(*path))
25242524
AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
25252525
uv_fs_chmod, *path, mode);
2526-
} else { // chmod(path, mode, undefined, ctx)
2527-
CHECK_EQ(argc, 4);
2528-
FSReqWrapSync req_wrap_sync;
2526+
} else { // chmod(path, mode)
2527+
FSReqWrapSync req_wrap_sync("chmod", *path);
25292528
FS_SYNC_TRACE_BEGIN(chmod);
2530-
SyncCall(env, args[3], &req_wrap_sync, "chmod",
2531-
uv_fs_chmod, *path, mode);
2529+
SyncCallAndThrowOnError(env, &req_wrap_sync, uv_fs_chmod, *path, mode);
25322530
FS_SYNC_TRACE_END(chmod);
25332531
}
25342532
}
@@ -2549,17 +2547,15 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
25492547
CHECK(args[1]->IsInt32());
25502548
const int mode = args[1].As<Int32>()->Value();
25512549

2552-
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2553-
if (req_wrap_async != nullptr) { // fchmod(fd, mode, req)
2550+
if (argc > 2) { // fchmod(fd, mode, req)
2551+
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
25542552
FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHMOD, req_wrap_async)
25552553
AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
25562554
uv_fs_fchmod, fd, mode);
2557-
} else { // fchmod(fd, mode, undefined, ctx)
2558-
CHECK_EQ(argc, 4);
2559-
FSReqWrapSync req_wrap_sync;
2555+
} else { // fchmod(fd, mode)
2556+
FSReqWrapSync req_wrap_sync("fchmod");
25602557
FS_SYNC_TRACE_BEGIN(fchmod);
2561-
SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2562-
uv_fs_fchmod, fd, mode);
2558+
SyncCallAndThrowOnError(env, &req_wrap_sync, uv_fs_fchmod, fd, mode);
25632559
FS_SYNC_TRACE_END(fchmod);
25642560
}
25652561
}

typings/internalBinding/fs.d.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ declare namespace InternalFSBinding {
6161
function access(path: StringOrBuffer, mode: number, usePromises: typeof kUsePromises): Promise<void>;
6262

6363
function chmod(path: string, mode: number, req: FSReqCallback): void;
64-
function chmod(path: string, mode: number, req: undefined, ctx: FSSyncContext): void;
64+
function chmod(path: string, mode: number): void;
6565
function chmod(path: string, mode: number, usePromises: typeof kUsePromises): Promise<void>;
6666

6767
function chown(path: string, uid: number, gid: number, req: FSReqCallback): void;
@@ -76,7 +76,7 @@ declare namespace InternalFSBinding {
7676
function copyFile(src: StringOrBuffer, dest: StringOrBuffer, mode: number, usePromises: typeof kUsePromises): Promise<void>;
7777

7878
function fchmod(fd: number, mode: number, req: FSReqCallback): void;
79-
function fchmod(fd: number, mode: number, req: undefined, ctx: FSSyncContext): void;
79+
function fchmod(fd: number, mode: number): void;
8080
function fchmod(fd: number, mode: number, usePromises: typeof kUsePromises): Promise<void>;
8181

8282
function fchown(fd: number, uid: number, gid: number, req: FSReqCallback): void;

0 commit comments

Comments
 (0)