Skip to content

Commit 395df96

Browse files
CanadaHonkanonrig
authored andcommitted
fs: improve error perf of sync chmod+fchmod
1 parent dc1c50b commit 395df96

5 files changed

Lines changed: 121 additions & 24 deletions

File tree

benchmark/fs/bench-chmodSync.js

Lines changed: 41 additions & 0 deletions
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

Lines changed: 60 additions & 0 deletions
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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,11 +1908,10 @@ function fchmod(fd, mode, callback) {
19081908
* @returns {void}
19091909
*/
19101910
function fchmodSync(fd, mode) {
1911-
fd = getValidatedFd(fd);
1912-
mode = parseFileMode(mode, 'mode');
1913-
const ctx = {};
1914-
binding.fchmod(fd, mode, undefined, ctx);
1915-
handleErrorFromBinding(ctx);
1911+
binding.fchmod(
1912+
getValidatedFd(fd),
1913+
parseFileMode(mode, 'mode'),
1914+
);
19161915
}
19171916

19181917
/**
@@ -1987,9 +1986,10 @@ function chmodSync(path, mode) {
19871986
path = getValidatedPath(path);
19881987
mode = parseFileMode(mode, 'mode');
19891988

1990-
const ctx = { path };
1991-
binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx);
1992-
handleErrorFromBinding(ctx);
1989+
binding.chmod(
1990+
pathModule.toNamespacedPath(path),
1991+
mode,
1992+
);
19931993
}
19941994

19951995
/**

src/node_file.cc

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2506,18 +2506,16 @@ static void Chmod(const FunctionCallbackInfo<Value>& args) {
25062506
CHECK(args[1]->IsInt32());
25072507
int mode = args[1].As<Int32>()->Value();
25082508

2509-
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2510-
if (req_wrap_async != nullptr) { // chmod(path, mode, req)
2509+
if (argc > 2) { // chmod(path, mode, req)
2510+
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
25112511
FS_ASYNC_TRACE_BEGIN1(
25122512
UV_FS_CHMOD, req_wrap_async, "path", TRACE_STR_COPY(*path))
25132513
AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs,
25142514
uv_fs_chmod, *path, mode);
2515-
} else { // chmod(path, mode, undefined, ctx)
2516-
CHECK_EQ(argc, 4);
2517-
FSReqWrapSync req_wrap_sync;
2515+
} else { // chmod(path, mode)
2516+
FSReqWrapSync req_wrap_sync("chmod", *path);
25182517
FS_SYNC_TRACE_BEGIN(chmod);
2519-
SyncCall(env, args[3], &req_wrap_sync, "chmod",
2520-
uv_fs_chmod, *path, mode);
2518+
SyncCallAndThrowOnError(env, &req_wrap_sync, uv_fs_chmod, *path, mode);
25212519
FS_SYNC_TRACE_END(chmod);
25222520
}
25232521
}
@@ -2538,17 +2536,15 @@ static void FChmod(const FunctionCallbackInfo<Value>& args) {
25382536
CHECK(args[1]->IsInt32());
25392537
const int mode = args[1].As<Int32>()->Value();
25402538

2541-
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
2542-
if (req_wrap_async != nullptr) { // fchmod(fd, mode, req)
2539+
if (argc > 2) { // fchmod(fd, mode, req)
2540+
FSReqBase* req_wrap_async = GetReqWrap(args, 2);
25432541
FS_ASYNC_TRACE_BEGIN0(UV_FS_FCHMOD, req_wrap_async)
25442542
AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs,
25452543
uv_fs_fchmod, fd, mode);
2546-
} else { // fchmod(fd, mode, undefined, ctx)
2547-
CHECK_EQ(argc, 4);
2548-
FSReqWrapSync req_wrap_sync;
2544+
} else { // fchmod(fd, mode)
2545+
FSReqWrapSync req_wrap_sync("fchmod");
25492546
FS_SYNC_TRACE_BEGIN(fchmod);
2550-
SyncCall(env, args[3], &req_wrap_sync, "fchmod",
2551-
uv_fs_fchmod, fd, mode);
2547+
SyncCallAndThrowOnError(env, &req_wrap_sync, uv_fs_fchmod, fd, mode);
25522548
FS_SYNC_TRACE_END(fchmod);
25532549
}
25542550
}

typings/internalBinding/fs.d.ts

Lines changed: 2 additions & 2 deletions
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)