From 84d1cf558ccfa6e29ed98383a9abb740fadf5cb9 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Sat, 5 Sep 2026 17:14:44 +0200 Subject: [PATCH] perf: extract archives off the caller's executor --- packages/oneclient_java/src/install.rs | 10 ++++- packages/polyio/src/archive.rs | 53 +++++++++++++++++++------- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/packages/oneclient_java/src/install.rs b/packages/oneclient_java/src/install.rs index f90b354b..dba03be9 100644 --- a/packages/oneclient_java/src/install.rs +++ b/packages/oneclient_java/src/install.rs @@ -74,7 +74,15 @@ pub async fn install_package( PackageArchive::TarGz => polyio::extract_tar_gz(&archive_path, &extract_root).await?, } - let executable = resolve_installed_executable(&extract_root, package); + // Walks the extract root and stats candidates, so it stays off the caller's + // executor for the same reason the extraction above does + let executable = { + let extract_root = extract_root.clone(); + let package = package.clone(); + tokio::task::spawn_blocking(move || resolve_installed_executable(&extract_root, &package)) + .await + .map_err(|err| polyio::IOError::from(std::io::Error::other(err)))? + }; #[cfg(unix)] { diff --git a/packages/polyio/src/archive.rs b/packages/polyio/src/archive.rs index c29d964a..e629e64a 100644 --- a/packages/polyio/src/archive.rs +++ b/packages/polyio/src/archive.rs @@ -135,15 +135,36 @@ pub async fn extract_zip( zip_path: impl AsRef, dest_path: impl AsRef, ) -> PolyIOResult<()> { - extract_zip_filtered( - zip_path, - dest_path, - None:: bool>, - None:: String>, - ) + let zip_path = zip_path.as_ref().to_path_buf(); + let dest_path = dest_path.as_ref().to_path_buf(); + + off_caller_thread(move || async move { + extract_zip_filtered( + zip_path, + dest_path, + None:: bool>, + None:: String>, + ) + .await + }) .await } +/// Inflating an archive is CPU work sitting between short async writes, and +/// installs are driven from freya's UI-thread executor, so a large extraction +/// run inline stalls rendering for as long as it takes +async fn off_caller_thread(work: F) -> PolyIOResult<()> +where + F: FnOnce() -> Fut + Send + 'static, + Fut: std::future::Future>, +{ + let handle = tokio::runtime::Handle::current(); + + tokio::task::spawn_blocking(move || handle.block_on(work())) + .await + .map_err(std::io::Error::other)? +} + #[tracing::instrument( level = "debug", skip(zip_path, dest_path, filter_entries, modify_entry_name), @@ -306,14 +327,20 @@ where ) )] pub async fn extract_tar_gz(archive: impl AsRef, dest: impl AsRef) -> PolyIOResult<()> { - crate::create_dir_all(&dest).await?; + let archive = archive.as_ref().to_path_buf(); + let dest = dest.as_ref().to_path_buf(); - let file = tokio::fs::File::open(archive).await?; - let buf_reader = tokio::io::BufReader::new(file); - let gzip_decoder = async_compression::tokio::bufread::GzipDecoder::new(buf_reader); + off_caller_thread(move || async move { + crate::create_dir_all(&dest).await?; - let mut tar_archive = tokio_tar::Archive::new(gzip_decoder); - tar_archive.unpack(dest).await?; + let file = tokio::fs::File::open(archive).await?; + let buf_reader = tokio::io::BufReader::new(file); + let gzip_decoder = async_compression::tokio::bufread::GzipDecoder::new(buf_reader); - Ok(()) + let mut tar_archive = tokio_tar::Archive::new(gzip_decoder); + tar_archive.unpack(dest).await?; + + Ok(()) + }) + .await } \ No newline at end of file