Skip to content

Commit

Permalink
accounts: retry filesystem operations in migrate_account()
Browse files Browse the repository at this point in the history
  • Loading branch information
link2xt committed Feb 15, 2023
1 parent 243f28f commit cae0b8e
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Changes
- deltachat-rpc-client: use `dataclass` for `Account`, `Chat`, `Contact` and `Message` #4042
- retry filesystem operations during account migration #4043

### Fixes
- deltachat-rpc-server: do not block stdin while processing the request. #4041
Expand Down
61 changes: 35 additions & 26 deletions src/accounts.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -150,27 +151,9 @@ impl Accounts {
if let Some(cfg) = self.config.get_account(id) {
let account_path = self.dir.join(cfg.dir);

// Spend up to 1 minute trying to remove the files.
// Files may remain locked up to 30 seconds due to r2d2 bug:
// https://github.com/sfackler/r2d2/issues/99
let mut counter = 0;
loop {
counter += 1;

if let Err(err) = fs::remove_dir_all(&account_path)
.await
.context("failed to remove account data")
{
if counter > 60 {
return Err(err);
}

// Wait 1 second and try again.
tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
} else {
break;
}
}
try_many_times(|| fs::remove_dir_all(&account_path))
.await
.context("failed to remove account data")?;
}
self.config.remove_account(id).await?;

Expand Down Expand Up @@ -202,10 +185,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() {
Expand All @@ -229,11 +212,10 @@ impl Accounts {
Ok(account_config.id)
}
Err(err) => {
// remove temp account
fs::remove_dir_all(std::path::PathBuf::from(&account_config.dir))
let account_path = std::path::PathBuf::from(&account_config.dir);
try_many_times(|| fs::remove_dir_all(&account_path))
.await
.context("failed to remove account data")?;

self.config.remove_account(account_config.id).await?;

// set selection back
Expand Down Expand Up @@ -488,6 +470,33 @@ impl Config {
}
}

/// Spend up to 1 minute trying to do the operation.
///
/// Files may remain locked up to 30 seconds due to r2d2 bug:
/// <https://github.com/sfackler/r2d2/issues/99>
async fn try_many_times<F, Fut, T>(f: F) -> std::result::Result<(), T>
where
F: Fn() -> Fut,
Fut: Future<Output = std::result::Result<(), T>>,
{
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 {
Expand Down

0 comments on commit cae0b8e

Please sign in to comment.