From 078def0ff8501bb07f3f286515acd8c6a2181037 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 17 Jul 2024 05:35:51 -0700 Subject: perf(ext/node): optimize fs.exists[Sync] (#24613) Use `access` on *nix and `GetFileAttributesW` on Windows. [Benchmark](https://paste.divy.work/p/-gq8Ark.js): ``` $ deno run -A bench.mjs # main (568dd) existsSync: 8980.636629ms $ target/release/deno run -A bench.mjs # this PR existsSync: 6448.7604519999995ms $ bun bench.mjs existsSync: 6562.88671ms $ node bench.mjs existsSync: 7740.064653ms ``` Ref https://github.com/denoland/deno/pull/24434#discussion_r1679777912 --- ext/fs/interface.rs | 3 +++ ext/fs/std_fs.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'ext/fs') diff --git a/ext/fs/interface.rs b/ext/fs/interface.rs index 2fdfa2186..09e16aff1 100644 --- a/ext/fs/interface.rs +++ b/ext/fs/interface.rs @@ -315,6 +315,9 @@ pub trait FileSystem: std::fmt::Debug + MaybeSend + MaybeSync { fn exists_sync(&self, path: &Path) -> bool { self.stat_sync(path).is_ok() } + async fn exists_async(&self, path: PathBuf) -> FsResult { + Ok(self.stat_async(path).await.is_ok()) + } fn read_text_file_lossy_sync( &self, diff --git a/ext/fs/std_fs.rs b/ext/fs/std_fs.rs index 7903700c3..7fc33a8ad 100644 --- a/ext/fs/std_fs.rs +++ b/ext/fs/std_fs.rs @@ -173,6 +173,15 @@ impl FileSystem for RealFs { spawn_blocking(move || lstat(&path)).await?.map(Into::into) } + fn exists_sync(&self, path: &Path) -> bool { + exists(path) + } + async fn exists_async(&self, path: PathBuf) -> FsResult { + spawn_blocking(move || exists(&path)) + .await + .map_err(Into::into) + } + fn realpath_sync(&self, path: &Path) -> FsResult { realpath(path) } @@ -837,6 +846,32 @@ fn stat_extra( } } +fn exists(path: &Path) -> bool { + #[cfg(unix)] + { + use nix::unistd::access; + use nix::unistd::AccessFlags; + access(path, AccessFlags::F_OK).is_ok() + } + + #[cfg(windows)] + { + use std::os::windows::ffi::OsStrExt; + use winapi::um::fileapi::GetFileAttributesW; + use winapi::um::fileapi::INVALID_FILE_ATTRIBUTES; + + let path = path + .as_os_str() + .encode_wide() + .chain(std::iter::once(0)) + .collect::>(); + // Safety: `path` is a null-terminated string + let attrs = unsafe { GetFileAttributesW(path.as_ptr()) }; + + attrs != INVALID_FILE_ATTRIBUTES + } +} + fn realpath(path: &Path) -> FsResult { Ok(deno_core::strip_unc_prefix(path.canonicalize()?)) } -- cgit v1.2.3