Skip to content

Commit

Permalink
fs: improve error performance of fs.writeSync
Browse files Browse the repository at this point in the history
  • Loading branch information
shubham9411 committed Nov 26, 2023
1 parent f8c27e6 commit 347181d
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 19 deletions.
20 changes: 20 additions & 0 deletions benchmark/fs/bench-writeFileSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

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

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

function main({ n, type }) {
const path = tmpdir.resolve(`new-file-${process.pid}`);

bench.start();
for (let i = 0; i < n; i++) {
fs.writeFileSync(path, 'Benchmark data.');
}
bench.end(n);
}
34 changes: 34 additions & 0 deletions benchmark/fs/bench-writeSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

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

const path = tmpdir.resolve(`new-file-${process.pid}`);
fs.writeFileSync(path, 'Some content.');

const bench = common.createBenchmark(main, {
type: ['valid', 'invalid'],
dataType: ['string', 'buffer'],
n: [1e5],
});

const stringData = 'Benchmark data.';
const bufferData = Buffer.from(stringData);

function main({ n, type, dataType }) {
const fd = type === 'valid' ? fs.openSync(path, 'r+') : 1 << 30;
const data = dataType === 'string' ? stringData : bufferData;

bench.start();
for (let i = 0; i < n; i++) {
try {
fs.writeSync(fd, data);
} catch {
// Continue regardless of error.
}
}
bench.end(n);
if (type === 'valid') fs.closeSync(fd);
}
8 changes: 2 additions & 6 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,6 @@ ObjectDefineProperty(write, kCustomPromisifyArgsSymbol,
*/
function writeSync(fd, buffer, offsetOrOptions, length, position) {
fd = getValidatedFd(fd);
const ctx = {};
let result;

let offset = offsetOrOptions;
Expand All @@ -922,18 +921,15 @@ function writeSync(fd, buffer, offsetOrOptions, length, position) {
if (typeof length !== 'number')
length = buffer.byteLength - offset;
validateOffsetLengthWrite(offset, length, buffer.byteLength);
result = binding.writeBuffer(fd, buffer, offset, length, position,
undefined, ctx);
result = binding.writeBuffer(fd, buffer, offset, length, position);
} else {
validateStringAfterArrayBufferView(buffer, 'buffer');
validateEncoding(buffer, length);

if (offset === undefined)
offset = null;
result = binding.writeString(fd, buffer, offset, length,
undefined, ctx);
result = binding.writeString(fd, buffer, offset, length);
}
handleErrorFromBinding(ctx);
return result;
}

Expand Down
30 changes: 17 additions & 13 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2033,7 +2033,7 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

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

CHECK(args[0]->IsInt32());
const int fd = args[0].As<Int32>()->Value();
Expand All @@ -2060,18 +2060,20 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
char* buf = buffer_data + off;
uv_buf_t uvbuf = uv_buf_init(buf, len);

FSReqBase* req_wrap_async = GetReqWrap(args, 5);
if (req_wrap_async != nullptr) { // write(fd, buffer, off, len, pos, req)
if (argc > 5) { // write(fd, buffer, off, len, pos, req)
FSReqBase* req_wrap_async = GetReqWrap(args, 5);
FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async)
AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger,
uv_fs_write, fd, &uvbuf, 1, pos);
} else { // write(fd, buffer, off, len, pos, undefined, ctx)
CHECK_EQ(argc, 7);
FSReqWrapSync req_wrap_sync;
} else { // write(fd, buffer, off, len, pos)
FSReqWrapSync req_wrap_sync("write");
FS_SYNC_TRACE_BEGIN(write);
int bytesWritten = SyncCall(env, args[6], &req_wrap_sync, "write",
uv_fs_write, fd, &uvbuf, 1, pos);
int bytesWritten = SyncCallAndThrowOnError(
env, &req_wrap_sync, uv_fs_write, fd, &uvbuf, 1, pos);
FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
if (is_uv_error(bytesWritten)) {
return;
}
args.GetReturnValue().Set(bytesWritten);
}
}
Expand Down Expand Up @@ -2208,9 +2210,8 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
} else {
req_wrap_async->SetReturnValue(args);
}
} else { // write(fd, string, pos, enc, undefined, ctx)
CHECK_EQ(argc, 6);
FSReqWrapSync req_wrap_sync;
} else { // write(fd, string, pos, enc)
FSReqWrapSync req_wrap_sync("write");
FSReqBase::FSReqBuffer stack_buffer;
if (buf == nullptr) {
if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
Expand All @@ -2225,9 +2226,12 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
}
uv_buf_t uvbuf = uv_buf_init(buf, len);
FS_SYNC_TRACE_BEGIN(write);
int bytesWritten = SyncCall(env, args[5], &req_wrap_sync, "write",
uv_fs_write, fd, &uvbuf, 1, pos);
int bytesWritten = SyncCallAndThrowOnError(
env, &req_wrap_sync, uv_fs_write, fd, &uvbuf, 1, pos);
FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten);
if (is_uv_error(bytesWritten)) {
return;
}
args.GetReturnValue().Set(bytesWritten);
}
}
Expand Down

0 comments on commit 347181d

Please sign in to comment.