1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

perf(node/fs): faster existsSync when not exists (#21458)

This commit is contained in:
David Sherret 2023-12-04 16:05:40 -05:00 committed by GitHub
parent 9eb25e3cff
commit a24d3e8763
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 13 deletions

View file

@ -3,7 +3,8 @@
import { assert, assertThrows } from "../../../test_util/std/assert/mod.ts"; import { assert, assertThrows } from "../../../test_util/std/assert/mod.ts";
import { join } from "node:path"; import { join } from "node:path";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"; import { existsSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
import { pathToAbsoluteFileUrl } from "../unit/test_util.ts";
Deno.test( Deno.test(
"[node/fs writeFileSync] write file without option", "[node/fs writeFileSync] write file without option",
@ -43,3 +44,39 @@ Deno.test(
); );
}, },
); );
Deno.test(
"[node/fs existsSync] path",
{ permissions: { read: true } },
() => {
assert(existsSync("cli/tests/testdata/assets/fixture.json"));
},
);
Deno.test(
"[node/fs existsSync] url",
{ permissions: { read: true } },
() => {
assert(existsSync(
pathToAbsoluteFileUrl("cli/tests/testdata/assets/fixture.json"),
));
},
);
Deno.test(
"[node/fs existsSync] no permission",
{ permissions: { read: false } },
() => {
assertThrows(() => {
existsSync("cli/tests/testdata/assets/fixture.json");
}, Deno.errors.PermissionDenied);
},
);
Deno.test(
"[node/fs existsSync] not exists",
{ permissions: { read: true } },
() => {
assert(!existsSync("bad_filename"));
},
);

View file

@ -50,7 +50,15 @@ pub trait NodePermissions {
url: &Url, url: &Url,
api_name: &str, api_name: &str,
) -> Result<(), AnyError>; ) -> Result<(), AnyError>;
fn check_read(&self, path: &Path) -> Result<(), AnyError>; #[inline(always)]
fn check_read(&self, path: &Path) -> Result<(), AnyError> {
self.check_read_with_api_name(path, None)
}
fn check_read_with_api_name(
&self,
path: &Path,
api_name: Option<&str>,
) -> Result<(), AnyError>;
fn check_sys(&self, kind: &str, api_name: &str) -> Result<(), AnyError>; fn check_sys(&self, kind: &str, api_name: &str) -> Result<(), AnyError>;
} }
@ -64,7 +72,11 @@ impl NodePermissions for AllowAllNodePermissions {
) -> Result<(), AnyError> { ) -> Result<(), AnyError> {
Ok(()) Ok(())
} }
fn check_read(&self, _path: &Path) -> Result<(), AnyError> { fn check_read_with_api_name(
&self,
_path: &Path,
_api_name: Option<&str>,
) -> Result<(), AnyError> {
Ok(()) Ok(())
} }
fn check_sys(&self, _kind: &str, _api_name: &str) -> Result<(), AnyError> { fn check_sys(&self, _kind: &str, _api_name: &str) -> Result<(), AnyError> {
@ -227,6 +239,7 @@ deno_core::extension!(deno_node,
ops::crypto::x509::op_node_x509_get_valid_to, ops::crypto::x509::op_node_x509_get_valid_to,
ops::crypto::x509::op_node_x509_get_serial_number, ops::crypto::x509::op_node_x509_get_serial_number,
ops::crypto::x509::op_node_x509_key_usage, ops::crypto::x509::op_node_x509_key_usage,
ops::fs::op_node_fs_exists_sync<P>,
ops::winerror::op_node_sys_to_uv_error, ops::winerror::op_node_sys_to_uv_error,
ops::v8::op_v8_cached_data_version_tag, ops::v8::op_v8_cached_data_version_tag,
ops::v8::op_v8_get_heap_statistics, ops::v8::op_v8_get_heap_statistics,

26
ext/node/ops/fs.rs Normal file
View file

@ -0,0 +1,26 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
use std::path::PathBuf;
use deno_core::error::AnyError;
use deno_core::op2;
use deno_core::OpState;
use deno_fs::FileSystemRc;
use crate::NodePermissions;
#[op2(fast)]
pub fn op_node_fs_exists_sync<P>(
state: &mut OpState,
#[string] path: String,
) -> Result<bool, AnyError>
where
P: NodePermissions + 'static,
{
let path = PathBuf::from(path);
state
.borrow_mut::<P>()
.check_read_with_api_name(&path, Some("node:fs.existsSync()"))?;
let fs = state.borrow::<FileSystemRc>();
Ok(fs.lstat_sync(&path).is_ok())
}

View file

@ -1,6 +1,7 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
pub mod crypto; pub mod crypto;
pub mod fs;
pub mod http; pub mod http;
pub mod http2; pub mod http2;
pub mod idna; pub mod idna;

View file

@ -2,7 +2,7 @@
// TODO(petamoriken): enable prefer-primordials for node polyfills // TODO(petamoriken): enable prefer-primordials for node polyfills
// deno-lint-ignore-file prefer-primordials // deno-lint-ignore-file prefer-primordials
const core = globalThis.__bootstrap.core;
import { pathFromURL } from "ext:deno_web/00_infra.js"; import { pathFromURL } from "ext:deno_web/00_infra.js";
type ExistsCallback = (exists: boolean) => void; type ExistsCallback = (exists: boolean) => void;
@ -35,10 +35,5 @@ Object.defineProperty(exists, kCustomPromisifiedSymbol, {
*/ */
export function existsSync(path: string | URL): boolean { export function existsSync(path: string | URL): boolean {
path = path instanceof URL ? pathFromURL(path) : path; path = path instanceof URL ? pathFromURL(path) : path;
try { return core.ops.op_node_fs_exists_sync(path);
Deno.lstatSync(path);
return true;
} catch (_err) {
return false;
}
} }

View file

@ -1376,8 +1376,12 @@ impl deno_node::NodePermissions for PermissionsContainer {
} }
#[inline(always)] #[inline(always)]
fn check_read(&self, path: &Path) -> Result<(), AnyError> { fn check_read_with_api_name(
self.0.lock().read.check(path, None) &self,
path: &Path,
api_name: Option<&str>,
) -> Result<(), AnyError> {
self.0.lock().read.check(path, api_name)
} }
fn check_sys(&self, kind: &str, api_name: &str) -> Result<(), AnyError> { fn check_sys(&self, kind: &str, api_name: &str) -> Result<(), AnyError> {

View file

@ -76,7 +76,11 @@ impl deno_node::NodePermissions for Permissions {
) -> Result<(), deno_core::error::AnyError> { ) -> Result<(), deno_core::error::AnyError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_read(&self, _p: &Path) -> Result<(), deno_core::error::AnyError> { fn check_read_with_api_name(
&self,
_p: &Path,
_api_name: Option<&str>,
) -> Result<(), deno_core::error::AnyError> {
unreachable!("snapshotting!") unreachable!("snapshotting!")
} }
fn check_sys( fn check_sys(