Skip to content

Commit

Permalink
fs: add fast api to copyFileSync
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Sep 10, 2023
1 parent 8a748c4 commit 6ff6a52
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 10 deletions.
23 changes: 23 additions & 0 deletions benchmark/fs/bench-copyFileSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';

const common = require('../common');
const fs = require('fs');
const tmpdir = require('../../test/common/tmpdir');


const bench = common.createBenchmark(main, {
n: [1e4],
});

function main({ n }) {
tmpdir.refresh();
bench.start();
for (let i = 0; i < n; i++) {
try {
fs.copyFileSync(__filename, tmpdir.resolve(`copy-file-bench-${process.pid}`));
} catch {
// do nothing
}
}
bench.end(n);
}
11 changes: 1 addition & 10 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2977,16 +2977,7 @@ function copyFile(src, dest, mode, callback) {
* @returns {void}
*/
function copyFileSync(src, dest, mode) {
src = getValidatedPath(src, 'src');
dest = getValidatedPath(dest, 'dest');

const ctx = { path: src, dest }; // non-prefixed

src = pathModule._makeLong(src);
dest = pathModule._makeLong(dest);
mode = getValidMode(mode, 'copyFile');
binding.copyFile(src, dest, mode, undefined, ctx);
handleErrorFromBinding(ctx);
syncFs.copyFile(src, dest, mode);
}

/**
Expand Down
16 changes: 16 additions & 0 deletions lib/internal/fs/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,24 @@ function access(path, mode) {
}
}

function copyFile(src, dest, mode) {
src = getValidatedPath(src, 'src');
dest = getValidatedPath(dest, 'dest');

const errno = syncBinding.copyFile(
pathModule.toNamespacedPath(src),
pathModule.toNamespacedPath(dest),
getValidMode(mode, 'copyFile'),
);

if (errno < 0) {
handleErrorFromBinding({ errno, syscall: 'copyfile', path: src, dest });
}
}

module.exports = {
readFileUtf8,
exists,
access,
copyFile,
};
6 changes: 6 additions & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ using CFunctionCallbackWithStrings =
bool (*)(v8::Local<v8::Value>,
const v8::FastOneByteString& input,
const v8::FastOneByteString& base);
using CFunctionCallbackWithStringsReturningInt =
int32_t (*)(v8::Local<v8::Value>,
const v8::FastOneByteString& input,
const v8::FastOneByteString& base,
int32_t flags);
using CFunctionWithUint32 = uint32_t (*)(v8::Local<v8::Value>,
const uint32_t input);

Expand All @@ -42,6 +47,7 @@ class ExternalReferenceRegistry {
V(CFunctionCallbackWithBool) \
V(CFunctionCallbackWithString) \
V(CFunctionCallbackWithStrings) \
V(CFunctionCallbackWithStringsReturningInt) \
V(CFunctionWithUint32) \
V(const v8::CFunctionInfo*) \
V(v8::FunctionCallback) \
Expand Down
53 changes: 53 additions & 0 deletions src/node_file_sync.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,54 @@ void BindingData::Deserialize(v8::Local<v8::Context> context,
CHECK_NOT_NULL(binding);
}

inline int32_t BindingData::CopyFileInternal(const std::string_view src,
const std::string_view dest,
int flags) {
uv_fs_t req;
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
FS_SYNC_TRACE_BEGIN(copyfile);
uv_fs_copyfile(nullptr, &req, src.data(), dest.data(), flags, nullptr);
FS_SYNC_TRACE_END(copyfile);

return int32_t(req.result);
}

void BindingData::CopyFile(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();

const int argc = args.Length();
CHECK_GE(argc, 3);

BufferValue src(isolate, args[0]);
CHECK_NOT_NULL(*src);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());

BufferValue dest(isolate, args[1]);
CHECK_NOT_NULL(*dest);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());

CHECK(args[2]->IsInt32());
const int flags = args[2].As<Int32>()->Value();

return args.GetReturnValue().Set(
CopyFileInternal(src.ToStringView(), dest.ToStringView(), flags));
}

int32_t BindingData::FastCopyFile(Local<Value> receiver,
const FastOneByteString& src,
const FastOneByteString& dest,
int32_t flags) {
// TODO(@anonrig): Add "THROW_IF_INSUFFICIENT_PERMISSIONS"
return CopyFileInternal(std::string_view(src.data, src.length),
std::string_view(dest.data, dest.length),
flags);
}

CFunction BindingData::fast_copy_file_(CFunction::Make(FastCopyFile));

void BindingData::Access(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
Expand Down Expand Up @@ -264,6 +312,8 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
SetMethodNoSideEffect(isolate, target, "access", Access);
SetFastMethodNoSideEffect(
isolate, target, "copyFile", CopyFile, &fast_copy_file_);
SetFastMethodNoSideEffect(isolate, target, "exists", Exists, &fast_exists_);
SetMethodNoSideEffect(isolate, target, "readFileUtf8", ReadFileUtf8);
}
Expand All @@ -279,6 +329,9 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
void BindingData::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(Access);
registry->Register(CopyFile);
registry->Register(FastCopyFile);
registry->Register(fast_copy_file_.GetTypeInfo());
registry->Register(Exists);
registry->Register(FastExists);
registry->Register(fast_exists_.GetTypeInfo());
Expand Down
10 changes: 10 additions & 0 deletions src/node_file_sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class BindingData : public SnapshotableObject {
SET_SELF_SIZE(BindingData)
SET_MEMORY_INFO_NAME(BindingData)

static void CopyFile(const v8::FunctionCallbackInfo<v8::Value>& args);
static int32_t FastCopyFile(v8::Local<v8::Value> receiver,
const v8::FastOneByteString& src,
const v8::FastOneByteString& dest,
int32_t flags);

static void Exists(const v8::FunctionCallbackInfo<v8::Value>& args);
static bool FastExists(v8::Local<v8::Value> receiver,
const v8::FastOneByteString& path);
Expand All @@ -47,8 +53,12 @@ class BindingData : public SnapshotableObject {
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);

private:
static v8::CFunction fast_copy_file_;
static v8::CFunction fast_exists_;

static int CopyFileInternal(const std::string_view src,
const std::string_view dest,
int flags);
static bool ExistsInternal(const std::string_view path);
};

Expand Down
2 changes: 2 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const fs = require('node:fs')
fs.copyFileSync(__filename, './test.txt')

0 comments on commit 6ff6a52

Please sign in to comment.