Skip to content

Commit

Permalink
fs: improve error performance for writeSync
Browse files Browse the repository at this point in the history
  • Loading branch information
pluris committed Oct 24, 2023
1 parent 2c4a332 commit c6e35e9
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 21 deletions.
54 changes: 54 additions & 0 deletions benchmark/fs/bench-writeSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
'use strict';

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

const path = tmpdir.resolve(`new-file-${process.pid}`);
const parameters = [Buffer.from('Benchmark data'),
0,
Buffer.byteLength('Benchmark data')];
const bench = common.createBenchmark(main, {
type: ['valid', 'invalid'],
n: [1e5],
});

function main({ n, type }) {
let fd;
let result;

switch (type) {
case 'valid':
fd = fs.openSync(path, 'w');

bench.start();
for (let i = 0; i < n; i++) {
result = fs.writeSync(fd, ...parameters);
}

bench.end(n);
assert(result);
fs.closeSync(fd);
break;
case 'invalid': {
fd = 1 << 30;
let hasError = false;
bench.start();
for (let i = 0; i < n; i++) {
try {
result = fs.writeSync(fd, ...parameters);
} catch {
hasError = true;
}
}

bench.end(n);
assert(hasError);
break;
}
default:
throw new Error('Invalid type');
}
}
8 changes: 2 additions & 6 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,6 @@ ObjectDefineProperty(write, kCustomPromisifyArgsSymbol,
*/
function writeSync(fd, buffer, offsetOrOptions, length, position) {
fd = getValidatedFd(fd);
const ctx = {};
let result;

let offset = offsetOrOptions;
Expand All @@ -921,18 +920,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
36 changes: 23 additions & 13 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2098,7 +2098,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 @@ -2125,18 +2125,23 @@ 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);
CHECK_NOT_NULL(req_wrap_async);
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 @@ -2273,9 +2278,9 @@ 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)
CHECK_EQ(argc, 4);
FSReqWrapSync req_wrap_sync("write");
FSReqBase::FSReqBuffer stack_buffer;
if (buf == nullptr) {
if (!StringBytes::StorageSize(isolate, value, enc).To(&len))
Expand All @@ -2290,9 +2295,14 @@ 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
4 changes: 2 additions & 2 deletions typings/internalBinding/fs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,15 @@ declare namespace InternalFSBinding {
function utimes(path: string, atime: number, mtime: number, usePromises: typeof kUsePromises): Promise<void>;

function writeBuffer(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number | null, req: FSReqCallback<number>): void;
function writeBuffer(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number | null, req: undefined, ctx: FSSyncContext): number;
function writeBuffer(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number | null): number;
function writeBuffer(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number | null, usePromises: typeof kUsePromises): Promise<number>;

function writeBuffers(fd: number, buffers: ArrayBufferView[], position: number, req: FSReqCallback<number>): void;
function writeBuffers(fd: number, buffers: ArrayBufferView[], position: number, req: undefined, ctx: FSSyncContext): number;
function writeBuffers(fd: number, buffers: ArrayBufferView[], position: number, usePromises: typeof kUsePromises): Promise<number>;

function writeString(fd: number, value: string, pos: unknown, encoding: unknown, req: FSReqCallback<number>): void;
function writeString(fd: number, value: string, pos: unknown, encoding: unknown, req: undefined, ctx: FSSyncContext): number;
function writeString(fd: number, value: string, pos: unknown, encoding: unknown): number;
function writeString(fd: number, value: string, pos: unknown, encoding: unknown, usePromises: typeof kUsePromises): Promise<number>;

function getFormatOfExtensionlessFile(url: string): ConstantsBinding['fs'];
Expand Down

0 comments on commit c6e35e9

Please sign in to comment.