diff options
author | Aaron O'Mullan <aaron.omullan@gmail.com> | 2021-09-16 20:28:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-16 20:28:15 +0200 |
commit | 00948a6d680f855dcd0b60628a4b97186496a58c (patch) | |
tree | c8e739c26b9e65612c6e527d55760bfabb2d03e3 /runtime/js/12_io.js | |
parent | 868f38d4528bae508fdb222402441ba374db0721 (diff) |
perf(runtime/fs): optimize readFile by using a single large buffer (#12057)
* perf(runtime/fs): optimize readFile by using a single large buffer
* handle extended/truncated files during read
Allocate an extra byte in our read buffer to detect "overflow" then fallback to unsized readAll for remainder of extended file, this is a slowpath that should rarely happen in practice
Diffstat (limited to 'runtime/js/12_io.js')
-rw-r--r-- | runtime/js/12_io.js | 86 |
1 files changed, 64 insertions, 22 deletions
diff --git a/runtime/js/12_io.js b/runtime/js/12_io.js index a15015351..d5cf14e55 100644 --- a/runtime/js/12_io.js +++ b/runtime/js/12_io.js @@ -11,6 +11,7 @@ const { Uint8Array, ArrayPrototypePush, + MathMin, TypedArrayPrototypeSubarray, TypedArrayPrototypeSet, } = window.__bootstrap.primordials; @@ -96,10 +97,7 @@ return nread === 0 ? null : nread; } - async function read( - rid, - buffer, - ) { + async function read(rid, buffer) { if (buffer.length === 0) { return 0; } @@ -117,10 +115,10 @@ return await core.opAsync("op_write_async", rid, data); } - const READ_PER_ITER = 32 * 1024; + const READ_PER_ITER = 16 * 1024; // 16kb, see https://github.com/denoland/deno/issues/10157 - async function readAll(r) { - return await readAllInner(r); + function readAll(r) { + return readAllInner(r); } async function readAllInner(r, options) { const buffers = []; @@ -138,20 +136,7 @@ throw new DOMException("The read operation was aborted.", "AbortError"); } - let totalLen = 0; - for (const buf of buffers) { - totalLen += buf.byteLength; - } - - const contents = new Uint8Array(totalLen); - - let n = 0; - for (const buf of buffers) { - TypedArrayPrototypeSet(contents, buf, n); - n += buf.byteLength; - } - - return contents; + return concatBuffers(buffers); } function readAllSync(r) { @@ -161,12 +146,16 @@ const buf = new Uint8Array(READ_PER_ITER); const read = r.readSync(buf); if (typeof read == "number") { - ArrayPrototypePush(buffers, new Uint8Array(buf.buffer, 0, read)); + ArrayPrototypePush(buffers, buf.subarray(0, read)); } else { break; } } + return concatBuffers(buffers); + } + + function concatBuffers(buffers) { let totalLen = 0; for (const buf of buffers) { totalLen += buf.byteLength; @@ -183,6 +172,57 @@ return contents; } + function readAllSyncSized(r, size) { + const buf = new Uint8Array(size + 1); // 1B to detect extended files + let cursor = 0; + + while (cursor < size) { + const sliceEnd = MathMin(size + 1, cursor + READ_PER_ITER); + const slice = buf.subarray(cursor, sliceEnd); + const read = r.readSync(slice); + if (typeof read == "number") { + cursor += read; + } else { + break; + } + } + + // Handle truncated or extended files during read + if (cursor > size) { + // Read remaining and concat + return concatBuffers([buf, readAllSync(r)]); + } else { // cursor == size + return buf.subarray(0, cursor); + } + } + + async function readAllInnerSized(r, size, options) { + const buf = new Uint8Array(size + 1); // 1B to detect extended files + let cursor = 0; + const signal = options?.signal ?? null; + while (!signal?.aborted && cursor < size) { + const sliceEnd = MathMin(size + 1, cursor + READ_PER_ITER); + const slice = buf.subarray(cursor, sliceEnd); + const read = await r.read(slice); + if (typeof read == "number") { + cursor += read; + } else { + break; + } + } + if (signal?.aborted) { + throw new DOMException("The read operation was aborted.", "AbortError"); + } + + // Handle truncated or extended files during read + if (cursor > size) { + // Read remaining and concat + return concatBuffers([buf, await readAllInner(r, options)]); + } else { + return buf.subarray(0, cursor); + } + } + window.__bootstrap.io = { iterSync, iter, @@ -195,5 +235,7 @@ readAll, readAllInner, readAllSync, + readAllSyncSized, + readAllInnerSized, }; })(this); |