Skip to content

Commit 6de6974

Browse files
committed
fs: add fast api to copyFileSync
1 parent 8a748c4 commit 6de6974

File tree

9 files changed

+172
-10
lines changed

9 files changed

+172
-10
lines changed

benchmark/fs/bench-copyFileSync.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const fs = require('fs');
5+
const tmpdir = require('../../test/common/tmpdir');
6+
7+
8+
const bench = common.createBenchmark(main, {
9+
n: [1e4],
10+
});
11+
12+
function main({ n }) {
13+
tmpdir.refresh();
14+
bench.start();
15+
for (let i = 0; i < n; i++) {
16+
try {
17+
fs.copyFileSync(__filename, tmpdir.resolve(`copy-file-bench-${process.pid}`));
18+
} catch {
19+
// do nothing
20+
}
21+
}
22+
bench.end(n);
23+
}

fs.csv

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"binary","filename","configuration","rate","time"
2+
"old","fs/bench-copyFileSync.js","n=10000",13616.3012604911,0.734413833
3+
"new","fs/bench-copyFileSync.js","n=10000",13694.96485786424,0.730195375
4+
"old","fs/bench-copyFileSync.js","n=10000",13739.399773134755,0.727833833
5+
"new","fs/bench-copyFileSync.js","n=10000",13699.708435407236,0.729942542
6+
"old","fs/bench-copyFileSync.js","n=10000",13617.464767870439,0.734351083
7+
"new","fs/bench-copyFileSync.js","n=10000",13770.125553154377,0.726209791
8+
"old","fs/bench-copyFileSync.js","n=10000",13556.822063999047,0.737636000
9+
"new","fs/bench-copyFileSync.js","n=10000",13151.13027994143,0.760390916
10+
"old","fs/bench-copyFileSync.js","n=10000",13591.630953240541,0.735746875
11+
"new","fs/bench-copyFileSync.js","n=10000",13373.484259825611,0.747748291
12+
"old","fs/bench-copyFileSync.js","n=10000",13061.165498109005,0.765628458
13+
"new","fs/bench-copyFileSync.js","n=10000",13400.680687575525,0.746230750
14+
"old","fs/bench-copyFileSync.js","n=10000",13461.548606886345,0.742856583
15+
"new","fs/bench-copyFileSync.js","n=10000",12885.627912724512,0.776058417
16+
"old","fs/bench-copyFileSync.js","n=10000",13369.552198935173,0.747968208
17+
"new","fs/bench-copyFileSync.js","n=10000",13449.725771725527,0.743509583
18+
"old","fs/bench-copyFileSync.js","n=10000",13022.627912503243,0.767894166
19+
"new","fs/bench-copyFileSync.js","n=10000",12588.888045587253,0.794351333
20+
"old","fs/bench-copyFileSync.js","n=10000",13382.409609186761,0.747249583
21+
"new","fs/bench-copyFileSync.js","n=10000",13395.875712079207,0.746498416
22+
"old","fs/bench-copyFileSync.js","n=10000",12979.300568621471,0.770457541
23+
"new","fs/bench-copyFileSync.js","n=10000",13537.097497199007,0.738710791
24+
"old","fs/bench-copyFileSync.js","n=10000",13445.54009431686,0.743741042
25+
"new","fs/bench-copyFileSync.js","n=10000",13254.133980293414,0.754481584
26+
"old","fs/bench-copyFileSync.js","n=10000",13477.873044940337,0.741956833
27+
"new","fs/bench-copyFileSync.js","n=10000",12765.20104074684,0.783379750
28+
"old","fs/bench-copyFileSync.js","n=10000",13311.925538413308,0.751206125
29+
"new","fs/bench-copyFileSync.js","n=10000",12993.160844497557,0.769635666
30+
"old","fs/bench-copyFileSync.js","n=10000",13785.116009808622,0.725420083
31+
"new","fs/bench-copyFileSync.js","n=10000",13453.389135749238,0.743307125
32+
"old","fs/bench-copyFileSync.js","n=10000",13576.532014056462,0.736565125
33+
"new","fs/bench-copyFileSync.js","n=10000",13593.95129307099,0.735621291
34+
"old","fs/bench-copyFileSync.js","n=10000",13077.568781881682,0.764668125
35+
"new","fs/bench-copyFileSync.js","n=10000",13635.626072953326,0.733373000
36+
"old","fs/bench-copyFileSync.js","n=10000",13455.474669075922,0.743191916
37+
"new","fs/bench-copyFileSync.js","n=10000",13276.039117307597,0.753236708
38+
"old","fs/bench-copyFileSync.js","n=10000",13296.166116981,0.752096500
39+
"new","fs/bench-copyFileSync.js","n=10000",13418.647591833682,0.745231584
40+
"old","fs/bench-copyFileSync.js","n=10000",12954.297782798225,0.771944583
41+
"new","fs/bench-copyFileSync.js","n=10000",12721.505259388312,0.786070500
42+
"old","fs/bench-copyFileSync.js","n=10000",13728.349814036528,0.728419667
43+
"new","fs/bench-copyFileSync.js","n=10000",13828.01919674765,0.723169375
44+
"old","fs/bench-copyFileSync.js","n=10000",13411.63118725588,0.745621458
45+
"new","fs/bench-copyFileSync.js","n=10000",13463.148004183964,0.742768333
46+
"old","fs/bench-copyFileSync.js","n=10000",12420.184155039242,0.805141041
47+
"new","fs/bench-copyFileSync.js","n=10000",13677.715411194868,0.731116250
48+
"old","fs/bench-copyFileSync.js","n=10000",13569.371040912953,0.736953833
49+
"new","fs/bench-copyFileSync.js","n=10000",13635.334019896036,0.733388708
50+
"old","fs/bench-copyFileSync.js","n=10000",13605.901112245407,0.734975208
51+
"new","fs/bench-copyFileSync.js","n=10000",13630.905858832957,0.733626958
52+
"old","fs/bench-copyFileSync.js","n=10000",13355.137821683535,0.748775500
53+
"new","fs/bench-copyFileSync.js","n=10000",13303.936812643457,0.751657208
54+
"old","fs/bench-copyFileSync.js","n=10000",13505.185303742704,0.740456334
55+
"new","fs/bench-copyFileSync.js","n=10000",13190.559439048982,0.758117959
56+
"old","fs/bench-copyFileSync.js","n=10000",13659.444222785054,0.732094208
57+
"new","fs/bench-copyFileSync.js","n=10000",13615.53032156341,0.734455417
58+
"old","fs/bench-copyFileSync.js","n=10000",13565.95095535666,0.737139625
59+
"new","fs/bench-copyFileSync.js","n=10000",12739.006987933875,0.784990542
60+
"old","fs/bench-copyFileSync.js","n=10000",13675.54329087248,0.731232375
61+
"new","fs/bench-copyFileSync.js","n=10000",13476.086251690203,0.742055209

lib/fs.js

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2977,16 +2977,7 @@ function copyFile(src, dest, mode, callback) {
29772977
* @returns {void}
29782978
*/
29792979
function copyFileSync(src, dest, mode) {
2980-
src = getValidatedPath(src, 'src');
2981-
dest = getValidatedPath(dest, 'dest');
2982-
2983-
const ctx = { path: src, dest }; // non-prefixed
2984-
2985-
src = pathModule._makeLong(src);
2986-
dest = pathModule._makeLong(dest);
2987-
mode = getValidMode(mode, 'copyFile');
2988-
binding.copyFile(src, dest, mode, undefined, ctx);
2989-
handleErrorFromBinding(ctx);
2980+
syncFs.copyFile(src, dest, mode);
29902981
}
29912982

29922983
/**

lib/internal/fs/sync.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,24 @@ function access(path, mode) {
4343
}
4444
}
4545

46+
function copyFile(src, dest, mode) {
47+
src = getValidatedPath(src, 'src');
48+
dest = getValidatedPath(dest, 'dest');
49+
50+
const errno = syncBinding.copyFile(
51+
pathModule.toNamespacedPath(src),
52+
pathModule.toNamespacedPath(dest),
53+
getValidMode(mode, 'copyFile'),
54+
);
55+
56+
if (errno < 0) {
57+
handleErrorFromBinding({ errno, syscall: 'copyfile', path: src, dest });
58+
}
59+
}
60+
4661
module.exports = {
4762
readFileUtf8,
4863
exists,
4964
access,
65+
copyFile,
5066
};

node-main

90.3 MB
Binary file not shown.

src/node_external_reference.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ using CFunctionCallbackWithStrings =
2525
bool (*)(v8::Local<v8::Value>,
2626
const v8::FastOneByteString& input,
2727
const v8::FastOneByteString& base);
28+
using CFunctionCallbackWithStringsReturningInt =
29+
int32_t (*)(v8::Local<v8::Value>,
30+
const v8::FastOneByteString& input,
31+
const v8::FastOneByteString& base,
32+
int32_t flags);
2833
using CFunctionWithUint32 = uint32_t (*)(v8::Local<v8::Value>,
2934
const uint32_t input);
3035

@@ -42,6 +47,7 @@ class ExternalReferenceRegistry {
4247
V(CFunctionCallbackWithBool) \
4348
V(CFunctionCallbackWithString) \
4449
V(CFunctionCallbackWithStrings) \
50+
V(CFunctionCallbackWithStringsReturningInt) \
4551
V(CFunctionWithUint32) \
4652
V(const v8::CFunctionInfo*) \
4753
V(v8::FunctionCallback) \

src/node_file_sync.cc

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,54 @@ void BindingData::Deserialize(v8::Local<v8::Context> context,
122122
CHECK_NOT_NULL(binding);
123123
}
124124

125+
inline int32_t BindingData::CopyFileInternal(const std::string_view src,
126+
const std::string_view dest,
127+
int flags) {
128+
uv_fs_t req;
129+
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
130+
FS_SYNC_TRACE_BEGIN(copyfile);
131+
uv_fs_copyfile(nullptr, &req, src.data(), dest.data(), flags, nullptr);
132+
FS_SYNC_TRACE_END(copyfile);
133+
134+
return int32_t(req.result);
135+
}
136+
137+
void BindingData::CopyFile(const FunctionCallbackInfo<Value>& args) {
138+
Environment* env = Environment::GetCurrent(args);
139+
Isolate* isolate = env->isolate();
140+
141+
const int argc = args.Length();
142+
CHECK_GE(argc, 3);
143+
144+
BufferValue src(isolate, args[0]);
145+
CHECK_NOT_NULL(*src);
146+
THROW_IF_INSUFFICIENT_PERMISSIONS(
147+
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
148+
149+
BufferValue dest(isolate, args[1]);
150+
CHECK_NOT_NULL(*dest);
151+
THROW_IF_INSUFFICIENT_PERMISSIONS(
152+
env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());
153+
154+
CHECK(args[2]->IsInt32());
155+
const int flags = args[2].As<Int32>()->Value();
156+
157+
return args.GetReturnValue().Set(
158+
CopyFileInternal(src.ToStringView(), dest.ToStringView(), flags));
159+
}
160+
161+
int32_t BindingData::FastCopyFile(Local<Value> receiver,
162+
const FastOneByteString& src,
163+
const FastOneByteString& dest,
164+
int32_t flags) {
165+
// TODO(@anonrig): Add "THROW_IF_INSUFFICIENT_PERMISSIONS"
166+
return CopyFileInternal(std::string_view(src.data, src.length),
167+
std::string_view(dest.data, dest.length),
168+
flags);
169+
}
170+
171+
CFunction BindingData::fast_copy_file_(CFunction::Make(FastCopyFile));
172+
125173
void BindingData::Access(const FunctionCallbackInfo<Value>& args) {
126174
Environment* env = Environment::GetCurrent(args);
127175
Isolate* isolate = env->isolate();
@@ -264,6 +312,8 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
264312
Local<ObjectTemplate> target) {
265313
Isolate* isolate = isolate_data->isolate();
266314
SetMethodNoSideEffect(isolate, target, "access", Access);
315+
SetFastMethodNoSideEffect(
316+
isolate, target, "copyFile", CopyFile, &fast_copy_file_);
267317
SetFastMethodNoSideEffect(isolate, target, "exists", Exists, &fast_exists_);
268318
SetMethodNoSideEffect(isolate, target, "readFileUtf8", ReadFileUtf8);
269319
}
@@ -279,6 +329,9 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
279329
void BindingData::RegisterExternalReferences(
280330
ExternalReferenceRegistry* registry) {
281331
registry->Register(Access);
332+
registry->Register(CopyFile);
333+
registry->Register(FastCopyFile);
334+
registry->Register(fast_copy_file_.GetTypeInfo());
282335
registry->Register(Exists);
283336
registry->Register(FastExists);
284337
registry->Register(fast_exists_.GetTypeInfo());

src/node_file_sync.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ class BindingData : public SnapshotableObject {
3131
SET_SELF_SIZE(BindingData)
3232
SET_MEMORY_INFO_NAME(BindingData)
3333

34+
static void CopyFile(const v8::FunctionCallbackInfo<v8::Value>& args);
35+
static int32_t FastCopyFile(v8::Local<v8::Value> receiver,
36+
const v8::FastOneByteString& src,
37+
const v8::FastOneByteString& dest,
38+
int32_t flags);
39+
3440
static void Exists(const v8::FunctionCallbackInfo<v8::Value>& args);
3541
static bool FastExists(v8::Local<v8::Value> receiver,
3642
const v8::FastOneByteString& path);
@@ -47,8 +53,12 @@ class BindingData : public SnapshotableObject {
4753
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
4854

4955
private:
56+
static v8::CFunction fast_copy_file_;
5057
static v8::CFunction fast_exists_;
5158

59+
static int CopyFileInternal(const std::string_view src,
60+
const std::string_view dest,
61+
int flags);
5262
static bool ExistsInternal(const std::string_view path);
5363
};
5464

test.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const fs = require('node:fs')
2+
fs.copyFileSync(__filename, './test.txt')

0 commit comments

Comments
 (0)