From 5d0961943c15914d4b088ddf97db361f99b52c66 Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Tue, 27 Oct 2026 19:29:11 +0800 Subject: [PATCH] perf(backup): extract archive off the runtime Run File::open, ZipArchive::new and the extraction of the backup archive inside spawn_blocking. Extracting a multi-file backup blocked a tokio worker for hundreds of milliseconds to seconds while the runtime kept serving other work on the remaining workers. Move the PROFILE_WRITE_LOCK acquisition after the extraction, right before finalize_restored_verge_config: the lock protects the config-data transition (extracted files reloaded into drafts), not the plain filesystem writes, so profile operations no longer queue behind the blocking unzip. --- src-tauri/src/feat/backup.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src-tauri/src/feat/backup.rs b/src-tauri/src/feat/backup.rs index 38745f635..802b37bae 100644 --- a/src-tauri/src/feat/backup.rs +++ b/src-tauri/src/feat/backup.rs @@ -161,10 +161,18 @@ pub async fn restore_webdav_backup(filename: String) -> Result<()> { })?; let value = backup_storage_path.clone(); - let file = AsyncHandler::spawn_blocking(move || std::fs::File::open(&value)).await??; - let mut zip = zip::ZipArchive::new(file)?; + let home_dir = app_home_dir()?; + AsyncHandler::spawn_blocking(move || -> Result<()> { + let file = std::fs::File::open(&value)?; + let mut zip = zip::ZipArchive::new(file)?; + zip.extract(&home_dir)?; + Ok(()) + }) + .await + .map_err(|join| anyhow!("backup extraction task failed: {join}"))??; + + // Held for the config-data transition only; extraction is plain filesystem work. let _profile_write = crate::config::profiles::PROFILE_WRITE_LOCK.lock().await; - zip.extract(app_home_dir()?)?; let res = finalize_restored_verge_config(webdav_url, webdav_username, webdav_password).await; let _ = backup_storage_path.remove_if_exists().await; res @@ -344,10 +352,18 @@ pub async fn restore_local_backup(filename: String) -> Result<()> { ) }; - let file = AsyncHandler::spawn_blocking(move || std::fs::File::open(&target_path)).await??; - let mut zip = zip::ZipArchive::new(file)?; + let home_dir = app_home_dir()?; + AsyncHandler::spawn_blocking(move || -> Result<()> { + let file = std::fs::File::open(&target_path)?; + let mut zip = zip::ZipArchive::new(file)?; + zip.extract(&home_dir)?; + Ok(()) + }) + .await + .map_err(|join| anyhow!("backup extraction task failed: {join}"))??; + + // Held for the config-data transition only; extraction is plain filesystem work. let _profile_write = crate::config::profiles::PROFILE_WRITE_LOCK.lock().await; - zip.extract(app_home_dir()?)?; finalize_restored_verge_config(webdav_url, webdav_username, webdav_password).await?; Ok(()) }