From 3c2e4ad1dbd5918abf6ed61b26156a1946cc1644 Mon Sep 17 00:00:00 2001 From: Ilyas Shabi Date: Wed, 4 Oct 2023 15:33:05 +0200 Subject: [PATCH] fs: improve writevSync performance --- benchmark/fs/bench-writevSync.js | 56 ++++++++++++++++++++++++++++++++ lib/fs.js | 7 +--- src/node_file.cc | 18 +++++----- 3 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 benchmark/fs/bench-writevSync.js diff --git a/benchmark/fs/bench-writevSync.js b/benchmark/fs/bench-writevSync.js new file mode 100644 index 00000000000000..756a8e38d076e2 --- /dev/null +++ b/benchmark/fs/bench-writevSync.js @@ -0,0 +1,56 @@ +'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}`); +fs.writeFileSync(path, 'Some content.'); + +const bench = common.createBenchmark(main, { + type: ['valid', 'invalid'], + n: [1e5], +}); + +const buffer = Buffer.from('Benchmark data.'); + +function main({ n, type }) { + let fd; + let result; + switch (type) { + case 'valid': + fd = fs.openSync(path, 'r+'); + + bench.start(); + for (let i = 0; i < n; i++) { + try { + result = fs.writevSync(fd, [buffer]); + } catch { + // + } + } + bench.end(n); + assert(result); + fs.closeSync(fd); + break; + case 'invalid': + fd = tmpdir.resolve(`.non-existing-file-${process.pid}`); + let hasError = false; + bench.start(); + for (let i = 0; i < n; i++) { + try { + result = fs.writevSync(fd, [buffer]); + } catch { + hasError = true; + } + } + bench.end(n); + assert(hasError); + + break; + default: + throw new Error('Invalid type'); + } +} diff --git a/lib/fs.js b/lib/fs.js index 3ff5cff2d3fb9a..5d245e9d19edcb 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -998,15 +998,10 @@ function writevSync(fd, buffers, position) { return 0; } - const ctx = {}; - if (typeof position !== 'number') position = null; - const result = binding.writeBuffers(fd, buffers, position, undefined, ctx); - - handleErrorFromBinding(ctx); - return result; + return binding.writeBuffers(fd, buffers, position); } /** diff --git a/src/node_file.cc b/src/node_file.cc index 74476be54f9b5d..32083a9f875358 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2205,18 +2205,20 @@ static void WriteBuffers(const FunctionCallbackInfo& args) { iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk)); } - FSReqBase* req_wrap_async = GetReqWrap(args, 3); - if (req_wrap_async != nullptr) { // writeBuffers(fd, chunks, pos, req) - FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async) - AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger, + if (argc > 3) { // writeBuffers(fd, chunks, pos, req) + FSReqBase* req_wrap_async = GetReqWrap(args, 3); + FS_ASYNC_TRACE_BEGIN0(UV_FS_WRITE, req_wrap_async) + AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger, uv_fs_write, fd, *iovs, iovs.length(), pos); - } else { // writeBuffers(fd, chunks, pos, undefined, ctx) - CHECK_EQ(argc, 5); - FSReqWrapSync req_wrap_sync; + } else { // writeBuffers(fd, chunks, pos) + FSReqWrapSync req_wrap_sync("write"); FS_SYNC_TRACE_BEGIN(write); - int bytesWritten = SyncCall(env, args[4], &req_wrap_sync, "write", + int bytesWritten = SyncCallAndThrowOnError(env, &req_wrap_sync, uv_fs_write, fd, *iovs, iovs.length(), pos); FS_SYNC_TRACE_END(write, "bytesWritten", bytesWritten); + if (is_uv_error(bytesWritten)) { + return; + } args.GetReturnValue().Set(bytesWritten); } }