0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 17:34:47 -05:00

perf(runtime): optimize Deno.file open & stream (#15496)

This commit is contained in:
Divy Srivastava 2022-08-19 15:54:40 +05:30 committed by GitHub
parent 8bdcec1c84
commit 9e576dff7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 35 deletions

View file

@ -23,6 +23,11 @@ Deno.bench("perf_now", { n: 5e5 }, () => {
performance.now(); performance.now();
}); });
Deno.bench("open_file_sync", () => {
const file = Deno.openSync("./cli/bench/testdata/128k.bin");
file.close();
});
// A common "language feature", that should be fast // A common "language feature", that should be fast
// also a decent representation of a non-trivial JSON-op // also a decent representation of a non-trivial JSON-op
{ {

View file

@ -7,7 +7,7 @@ const { serve } = Deno;
const path = new URL("../testdata/128k.bin", import.meta.url).pathname; const path = new URL("../testdata/128k.bin", import.meta.url).pathname;
function handler() { function handler() {
const file = Deno.openSync(path, { read: true }); const file = Deno.openSync(path);
return new Response(file.readable); return new Response(file.readable);
} }

View file

@ -658,7 +658,9 @@
* @returns {ReadableStream<Uint8Array>} * @returns {ReadableStream<Uint8Array>}
*/ */
function readableStreamForRid(rid, unrefCallback) { function readableStreamForRid(rid, unrefCallback) {
const stream = new ReadableStream({ const stream = webidl.createBranded(ReadableStream);
stream[_maybeRid] = rid;
const underlyingSource = {
type: "bytes", type: "bytes",
async pull(controller) { async pull(controller) {
const v = controller.byobRequest.view; const v = controller.byobRequest.view;
@ -685,9 +687,15 @@
core.tryClose(rid); core.tryClose(rid);
}, },
autoAllocateChunkSize: DEFAULT_CHUNK_SIZE, autoAllocateChunkSize: DEFAULT_CHUNK_SIZE,
}); };
initializeReadableStream(stream);
setUpReadableByteStreamControllerFromUnderlyingSource(
stream,
underlyingSource,
underlyingSource,
0,
);
stream[_maybeRid] = rid;
return stream; return stream;
} }
@ -714,7 +722,6 @@
} }
return true; return true;
} }
/** /**
* @template T * @template T
* @param {{ [_queue]: Array<ValueWithSize<T | _close>>, [_queueTotalSize]: number }} container * @param {{ [_queue]: Array<ValueWithSize<T | _close>>, [_queueTotalSize]: number }} container

View file

@ -33,12 +33,14 @@
function openSync( function openSync(
path, path,
options = { read: true }, options,
) { ) {
checkOpenOptions(options); if (options) checkOpenOptions(options);
const mode = options?.mode; const mode = options?.mode;
const rid = ops.op_open_sync( const rid = ops.op_open_sync(
{ path: pathFromURL(path), options, mode }, pathFromURL(path),
options,
mode,
); );
return new FsFile(rid); return new FsFile(rid);
@ -46,13 +48,15 @@
async function open( async function open(
path, path,
options = { read: true }, options,
) { ) {
checkOpenOptions(options); if (options) checkOpenOptions(options);
const mode = options?.mode; const mode = options?.mode;
const rid = await core.opAsync( const rid = await core.opAsync(
"op_open_async", "op_open_async",
{ path: pathFromURL(path), options, mode }, pathFromURL(path),
options,
mode,
); );
return new FsFile(rid); return new FsFile(rid);

View file

@ -128,15 +128,18 @@ pub struct OpenOptions {
create_new: bool, create_new: bool,
} }
#[inline]
fn open_helper( fn open_helper(
state: &mut OpState, state: &mut OpState,
args: &OpenArgs, path: &str,
mode: Option<u32>,
options: Option<&OpenOptions>,
) -> Result<(PathBuf, std::fs::OpenOptions), AnyError> { ) -> Result<(PathBuf, std::fs::OpenOptions), AnyError> {
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(path).to_path_buf();
let mut open_options = std::fs::OpenOptions::new(); let mut open_options = std::fs::OpenOptions::new();
if let Some(mode) = args.mode { if let Some(mode) = mode {
// mode only used if creating the file on Unix // mode only used if creating the file on Unix
// if not specified, defaults to 0o666 // if not specified, defaults to 0o666
#[cfg(unix)] #[cfg(unix)]
@ -149,33 +152,48 @@ fn open_helper(
} }
let permissions = state.borrow_mut::<Permissions>(); let permissions = state.borrow_mut::<Permissions>();
let options = &args.options;
if options.read { match options {
permissions.read.check(&path)?; None => {
permissions.read.check(&path)?;
open_options
.read(true)
.create(false)
.write(false)
.truncate(false)
.append(false)
.create_new(false);
}
Some(options) => {
if options.read {
permissions.read.check(&path)?;
}
if options.write || options.append {
permissions.write.check(&path)?;
}
open_options
.read(options.read)
.create(options.create)
.write(options.write)
.truncate(options.truncate)
.append(options.append)
.create_new(options.create_new);
}
} }
if options.write || options.append {
permissions.write.check(&path)?;
}
open_options
.read(options.read)
.create(options.create)
.write(options.write)
.truncate(options.truncate)
.append(options.append)
.create_new(options.create_new);
Ok((path, open_options)) Ok((path, open_options))
} }
#[op] #[op]
fn op_open_sync( fn op_open_sync(
state: &mut OpState, state: &mut OpState,
args: OpenArgs, path: String,
options: Option<OpenOptions>,
mode: Option<u32>,
) -> Result<ResourceId, AnyError> { ) -> Result<ResourceId, AnyError> {
let (path, open_options) = open_helper(state, &args)?; let (path, open_options) = open_helper(state, &path, mode, options.as_ref())?;
let std_file = open_options.open(&path).map_err(|err| { let std_file = open_options.open(&path).map_err(|err| {
Error::new(err.kind(), format!("{}, open '{}'", err, path.display())) Error::new(err.kind(), format!("{}, open '{}'", err, path.display()))
})?; })?;
@ -187,9 +205,12 @@ fn op_open_sync(
#[op] #[op]
async fn op_open_async( async fn op_open_async(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
args: OpenArgs, path: String,
options: Option<OpenOptions>,
mode: Option<u32>,
) -> Result<ResourceId, AnyError> { ) -> Result<ResourceId, AnyError> {
let (path, open_options) = open_helper(&mut state.borrow_mut(), &args)?; let (path, open_options) =
open_helper(&mut state.borrow_mut(), &path, mode, options.as_ref())?;
let std_file = tokio::task::spawn_blocking(move || { let std_file = tokio::task::spawn_blocking(move || {
open_options.open(path.clone()).map_err(|err| { open_options.open(path.clone()).map_err(|err| {
Error::new(err.kind(), format!("{}, open '{}'", err, path.display())) Error::new(err.kind(), format!("{}, open '{}'", err, path.display()))
@ -238,7 +259,12 @@ fn op_write_file_sync(
args: WriteFileArgs, args: WriteFileArgs,
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
let (open_args, data) = args.into_open_args_and_data(); let (open_args, data) = args.into_open_args_and_data();
let (path, open_options) = open_helper(state, &open_args)?; let (path, open_options) = open_helper(
state,
&open_args.path,
open_args.mode,
Some(&open_args.options),
)?;
write_file(&path, open_options, &open_args, data) write_file(&path, open_options, &open_args, data)
} }
@ -256,7 +282,12 @@ async fn op_write_file_async(
None => None, None => None,
}; };
let (open_args, data) = args.into_open_args_and_data(); let (open_args, data) = args.into_open_args_and_data();
let (path, open_options) = open_helper(&mut *state.borrow_mut(), &open_args)?; let (path, open_options) = open_helper(
&mut *state.borrow_mut(),
&open_args.path,
open_args.mode,
Some(&open_args.options),
)?;
let write_future = tokio::task::spawn_blocking(move || { let write_future = tokio::task::spawn_blocking(move || {
write_file(&path, open_options, &open_args, data) write_file(&path, open_options, &open_args, data)
}); });