Skip to content

Commit 2b4baa4

Browse files
committed
fs: improve error performance for fs.renameSync
1 parent 783f64b commit 2b4baa4

5 files changed

Lines changed: 100 additions & 6 deletions

File tree

benchmark/fs/bench-renameSync.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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: ['invalid', 'valid'],
10+
n: [1e3],
11+
});
12+
13+
function main({ n, type }) {
14+
tmpdir.refresh();
15+
16+
switch (type) {
17+
case 'invalid': {
18+
bench.start();
19+
for (let i = 0; i < n; i++) {
20+
try {
21+
fs.renameSync(tmpdir.resolve(`.non-existing-file-${i}`), tmpdir.resolve(`.new-file-${i}`));
22+
} catch {
23+
// do nothing
24+
}
25+
}
26+
bench.end(n);
27+
28+
break;
29+
}
30+
case 'valid': {
31+
for (let i = 0; i < n; i++) {
32+
fs.writeFileSync(tmpdir.resolve(`.existing-file-${i}`), 'bench', 'utf8');
33+
}
34+
35+
bench.start();
36+
for (let i = 0; i < n; i++) {
37+
try {
38+
fs.renameSync(
39+
tmpdir.resolve(`.existing-file-${i}`),
40+
tmpdir.resolve(`.new-existing-file-${i}`),
41+
);
42+
} catch {
43+
// do nothing
44+
}
45+
}
46+
47+
bench.end(n);
48+
break;
49+
}
50+
default:
51+
throw new Error('Invalid type');
52+
}
53+
}

lib/fs.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,12 +1015,7 @@ function rename(oldPath, newPath, callback) {
10151015
* @returns {void}
10161016
*/
10171017
function renameSync(oldPath, newPath) {
1018-
oldPath = getValidatedPath(oldPath, 'oldPath');
1019-
newPath = getValidatedPath(newPath, 'newPath');
1020-
const ctx = { path: oldPath, dest: newPath };
1021-
binding.rename(pathModule.toNamespacedPath(oldPath),
1022-
pathModule.toNamespacedPath(newPath), undefined, ctx);
1023-
handleErrorFromBinding(ctx);
1018+
return syncFs.rename(oldPath, newPath);
10241019
}
10251020

10261021
/**

lib/internal/fs/sync.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ function unlink(path) {
9393
return binding.unlinkSync(path);
9494
}
9595

96+
function rename(oldPath, newPath) {
97+
oldPath = getValidatedPath(oldPath, 'oldPath');
98+
newPath = getValidatedPath(newPath, 'newPath');
99+
return binding.renameSync(
100+
pathModule.toNamespacedPath(oldPath),
101+
pathModule.toNamespacedPath(newPath),
102+
);
103+
}
104+
96105
module.exports = {
97106
readFileUtf8,
98107
exists,
@@ -103,4 +112,5 @@ module.exports = {
103112
open,
104113
close,
105114
unlink,
115+
rename,
106116
};

src/node_file.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,38 @@ static void Rename(const FunctionCallbackInfo<Value>& args) {
15681568
}
15691569
}
15701570

1571+
static void RenameSync(const FunctionCallbackInfo<Value>& args) {
1572+
Environment* env = Environment::GetCurrent(args);
1573+
Isolate* isolate = env->isolate();
1574+
1575+
CHECK_EQ(args.Length(), 2);
1576+
1577+
BufferValue old_path(isolate, args[0]);
1578+
CHECK_NOT_NULL(*old_path);
1579+
auto view_old_path = old_path.ToStringView();
1580+
THROW_IF_INSUFFICIENT_PERMISSIONS(
1581+
env, permission::PermissionScope::kFileSystemRead, view_old_path);
1582+
THROW_IF_INSUFFICIENT_PERMISSIONS(
1583+
env, permission::PermissionScope::kFileSystemWrite, view_old_path);
1584+
1585+
BufferValue new_path(isolate, args[1]);
1586+
CHECK_NOT_NULL(*new_path);
1587+
THROW_IF_INSUFFICIENT_PERMISSIONS(
1588+
env,
1589+
permission::PermissionScope::kFileSystemWrite,
1590+
new_path.ToStringView());
1591+
1592+
uv_fs_t req;
1593+
auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
1594+
FS_SYNC_TRACE_BEGIN(rename);
1595+
int err = uv_fs_rename(nullptr, &req, *old_path, *new_path, nullptr);
1596+
FS_SYNC_TRACE_END(rename);
1597+
1598+
if (err < 0) {
1599+
return env->ThrowUVException(err, "rename", nullptr, *old_path, *new_path);
1600+
}
1601+
}
1602+
15711603
static void FTruncate(const FunctionCallbackInfo<Value>& args) {
15721604
Environment* env = Environment::GetCurrent(args);
15731605

@@ -3395,6 +3427,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
33953427
SetMethod(isolate, target, "fdatasync", Fdatasync);
33963428
SetMethod(isolate, target, "fsync", Fsync);
33973429
SetMethod(isolate, target, "rename", Rename);
3430+
SetMethod(isolate, target, "renameSync", RenameSync);
33983431
SetMethod(isolate, target, "ftruncate", FTruncate);
33993432
SetMethod(isolate, target, "rmdir", RMDir);
34003433
SetMethod(isolate, target, "mkdir", MKDir);
@@ -3521,6 +3554,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
35213554
registry->Register(Fdatasync);
35223555
registry->Register(Fsync);
35233556
registry->Register(Rename);
3557+
registry->Register(RenameSync);
35243558
registry->Register(FTruncate);
35253559
registry->Register(RMDir);
35263560
registry->Register(MKDir);

typings/internalBinding/fs.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ declare namespace InternalFSBinding {
180180
function rename(oldPath: string, newPath: string, req: FSReqCallback): void;
181181
function rename(oldPath: string, newPath: string, req: undefined, ctx: FSSyncContext): void;
182182
function rename(oldPath: string, newPath: string, usePromises: typeof kUsePromises): Promise<void>;
183+
function renameSync(oldPath: string, newPath: string): void;
183184

184185
function rmdir(path: string, req: FSReqCallback): void;
185186
function rmdir(path: string, req: undefined, ctx: FSSyncContext): void;
@@ -261,6 +262,7 @@ export interface FsBinding {
261262
readlink: typeof InternalFSBinding.readlink;
262263
realpath: typeof InternalFSBinding.realpath;
263264
rename: typeof InternalFSBinding.rename;
265+
renameSync: typeof InternalFSBinding.renameSync;
264266
rmdir: typeof InternalFSBinding.rmdir;
265267
stat: typeof InternalFSBinding.stat;
266268
symlink: typeof InternalFSBinding.symlink;

0 commit comments

Comments
 (0)