From 1478f321ae8cf99f2b8dfc29f913f41390092fef Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 25 Oct 2023 16:04:25 +0000 Subject: [PATCH] fix: restore `try_many_times` workaround Even though r2d2 connection pool is removed, deleting accounts still fails in Windows CI. This reverts commit e88f21c010fada6c8f59acce1e73055881bfc46d. `try_many_times` documentation is modified to explain why the workaround is still needed. --- src/accounts.rs | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/accounts.rs b/src/accounts.rs index 7cbe1cea4c..82c7489552 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -1,6 +1,7 @@ //! # Account manager module. use std::collections::BTreeMap; +use std::future::Future; use std::path::{Path, PathBuf}; use anyhow::{ensure, Context as _, Result}; @@ -155,7 +156,7 @@ impl Accounts { if let Some(cfg) = self.config.get_account(id) { let account_path = self.dir.join(cfg.dir); - fs::remove_dir_all(&account_path) + try_many_times(|| fs::remove_dir_all(&account_path)) .await .context("failed to remove account data")?; } @@ -191,10 +192,10 @@ impl Accounts { fs::create_dir_all(self.dir.join(&account_config.dir)) .await .context("failed to create dir")?; - fs::rename(&dbfile, &new_dbfile) + try_many_times(|| fs::rename(&dbfile, &new_dbfile)) .await .context("failed to rename dbfile")?; - fs::rename(&blobdir, &new_blobdir) + try_many_times(|| fs::rename(&blobdir, &new_blobdir)) .await .context("failed to rename blobdir")?; if walfile.exists() { @@ -219,7 +220,7 @@ impl Accounts { } Err(err) => { let account_path = std::path::PathBuf::from(&account_config.dir); - fs::remove_dir_all(&account_path) + try_many_times(|| fs::remove_dir_all(&account_path)) .await .context("failed to remove account data")?; self.config.remove_account(account_config.id).await?; @@ -560,6 +561,37 @@ impl Config { } } +/// Spend up to 1 minute trying to do the operation. +/// +/// Even if Delta Chat itself does not hold the file lock, +/// there may be other processes such as antivirus, +/// or the filesystem may be network-mounted. +/// +/// Without this workaround removing account may fail on Windows with an error +/// "The process cannot access the file because it is being used by another process. (os error 32)". +async fn try_many_times(f: F) -> std::result::Result<(), T> +where + F: Fn() -> Fut, + Fut: Future>, +{ + let mut counter = 0; + loop { + counter += 1; + + if let Err(err) = f().await { + if counter > 60 { + return Err(err); + } + + // Wait 1 second and try again. + tokio::time::sleep(std::time::Duration::from_millis(1000)).await; + } else { + break; + } + } + Ok(()) +} + /// Configuration of a single account. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] struct AccountConfig {