From 0cc176ef25a89e6a22c7d75f824be51c4a60716e Mon Sep 17 00:00:00 2001 From: Jungku Lee Date: Sat, 21 Oct 2023 11:00:00 +0900 Subject: [PATCH] fs: improve error performance for `readSync` PR-URL: https://github.com/nodejs/node/pull/50033 Refs: https://github.com/nodejs/performance/issues/106 Reviewed-By: Yagiz Nizipli Reviewed-By: Joyee Cheung --- benchmark/fs/bench-readSync.js | 57 +++++++++++++++++++++++++++++++++ lib/fs.js | 6 +--- src/node_file.cc | 19 +++++++---- typings/internalBinding/fs.d.ts | 2 +- 4 files changed, 71 insertions(+), 13 deletions(-) create mode 100644 benchmark/fs/bench-readSync.js diff --git a/benchmark/fs/bench-readSync.js b/benchmark/fs/bench-readSync.js new file mode 100644 index 00000000000000..a75d1750002f94 --- /dev/null +++ b/benchmark/fs/bench-readSync.js @@ -0,0 +1,57 @@ +'use strict'; + +const common = require('../common'); +const fs = require('fs'); +const tmpdir = require('../../test/common/tmpdir'); +tmpdir.refresh(); + +const bufferSize = 1024; +const sectorSize = 512; + +const bench = common.createBenchmark(main, { + type: ['existing', 'non-existing'], + n: [1e4], +}); + +function main({ n, type }) { + let fd; + + const tmpfile = { name: tmpdir.resolve(`.existing-file-${process.pid}`), + len: bufferSize * n }; + + + tmpfile.contents = Buffer.allocUnsafe(tmpfile.len); + + for (let offset = 0; offset < tmpfile.len; offset += sectorSize) { + const fillByte = 256 * Math.random(); + const nBytesToFill = Math.min(sectorSize, tmpfile.len - offset); + tmpfile.contents.fill(fillByte, offset, offset + nBytesToFill); + } + + fs.writeFileSync(tmpfile.name, tmpfile.contents); + + switch (type) { + case 'existing': + fd = fs.openSync(tmpfile.name, 'r', 0o666); + break; + case 'non-existing': + fd = 1 << 30; + break; + default: + new Error('Invalid type'); + } + + const buffer = Buffer.alloc(bufferSize); + + bench.start(); + for (let i = 0; i < n; i++) { + try { + fs.readSync(fd, buffer); + } catch { + // Continue regardless of error. + } + } + bench.end(n); + + if (type === 'existing') fs.closeSync(fd); +} diff --git a/lib/fs.js b/lib/fs.js index abc1c33bff0e50..53885d9478017f 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -751,11 +751,7 @@ function readSync(fd, buffer, offsetOrOptions, length, position) { validatePosition(position, 'position', length); } - const ctx = {}; - const result = binding.read(fd, buffer, offset, length, position, - undefined, ctx); - handleErrorFromBinding(ctx); - return result; + return binding.read(fd, buffer, offset, length, position); } /** diff --git a/src/node_file.cc b/src/node_file.cc index f20b8a5b8e3dfc..bda1774c012e7b 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2341,18 +2341,23 @@ static void Read(const FunctionCallbackInfo& 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) { // read(fd, buffer, offset, len, pos, req) + if (argc > 5) { // read(fd, buffer, offset, len, pos, req) + FSReqBase* req_wrap_async = GetReqWrap(args, 5); + CHECK_NOT_NULL(req_wrap_async); FS_ASYNC_TRACE_BEGIN0(UV_FS_READ, req_wrap_async) AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger, uv_fs_read, fd, &uvbuf, 1, pos); - } else { // read(fd, buffer, offset, len, pos, undefined, ctx) - CHECK_EQ(argc, 7); - FSReqWrapSync req_wrap_sync; + } else { // read(fd, buffer, offset, len, pos) + FSReqWrapSync req_wrap_sync("read"); FS_SYNC_TRACE_BEGIN(read); - const int bytesRead = SyncCall(env, args[6], &req_wrap_sync, "read", - uv_fs_read, fd, &uvbuf, 1, pos); + const int bytesRead = SyncCallAndThrowOnError( + env, &req_wrap_sync, uv_fs_read, fd, &uvbuf, 1, pos); FS_SYNC_TRACE_END(read, "bytesRead", bytesRead); + + if (is_uv_error(bytesRead)) { + return; + } + args.GetReturnValue().Set(bytesRead); } } diff --git a/typings/internalBinding/fs.d.ts b/typings/internalBinding/fs.d.ts index e3b74c9ab671a2..77f20e9550e30a 100644 --- a/typings/internalBinding/fs.d.ts +++ b/typings/internalBinding/fs.d.ts @@ -159,8 +159,8 @@ declare namespace InternalFSBinding { function openFileHandle(path: StringOrBuffer, flags: number, mode: number, usePromises: typeof kUsePromises): Promise; function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number, req: FSReqCallback): void; - function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number, req: undefined, ctx: FSSyncContext): number; function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number, usePromises: typeof kUsePromises): Promise; + function read(fd: number, buffer: ArrayBufferView, offset: number, length: number, position: number): number; function readBuffers(fd: number, buffers: ArrayBufferView[], position: number, req: FSReqCallback): void; function readBuffers(fd: number, buffers: ArrayBufferView[], position: number, req: undefined, ctx: FSSyncContext): number;