mirror of
https://github.com/chatmail/core.git
synced 2026-05-06 06:46:35 +03:00
accounts: retry filesystem operations in migrate_account()
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
### Changes
|
### Changes
|
||||||
- deltachat-rpc-client: use `dataclass` for `Account`, `Chat`, `Contact` and `Message` #4042
|
- deltachat-rpc-client: use `dataclass` for `Account`, `Chat`, `Contact` and `Message` #4042
|
||||||
- python: mark bindings as supporting typing according to PEP 561 #4045
|
- python: mark bindings as supporting typing according to PEP 561 #4045
|
||||||
|
- retry filesystem operations during account migration #4043
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- deltachat-rpc-server: do not block stdin while processing the request. #4041
|
- deltachat-rpc-server: do not block stdin while processing the request. #4041
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! # Account manager module.
|
//! # Account manager module.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::future::Future;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::{ensure, Context as _, Result};
|
use anyhow::{ensure, Context as _, Result};
|
||||||
@@ -150,27 +151,9 @@ impl Accounts {
|
|||||||
if let Some(cfg) = self.config.get_account(id) {
|
if let Some(cfg) = self.config.get_account(id) {
|
||||||
let account_path = self.dir.join(cfg.dir);
|
let account_path = self.dir.join(cfg.dir);
|
||||||
|
|
||||||
// Spend up to 1 minute trying to remove the files.
|
try_many_times(|| fs::remove_dir_all(&account_path))
|
||||||
// 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
|
.await
|
||||||
.context("failed to remove account data")
|
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.config.remove_account(id).await?;
|
self.config.remove_account(id).await?;
|
||||||
|
|
||||||
@@ -202,10 +185,10 @@ impl Accounts {
|
|||||||
fs::create_dir_all(self.dir.join(&account_config.dir))
|
fs::create_dir_all(self.dir.join(&account_config.dir))
|
||||||
.await
|
.await
|
||||||
.context("failed to create dir")?;
|
.context("failed to create dir")?;
|
||||||
fs::rename(&dbfile, &new_dbfile)
|
try_many_times(|| fs::rename(&dbfile, &new_dbfile))
|
||||||
.await
|
.await
|
||||||
.context("failed to rename dbfile")?;
|
.context("failed to rename dbfile")?;
|
||||||
fs::rename(&blobdir, &new_blobdir)
|
try_many_times(|| fs::rename(&blobdir, &new_blobdir))
|
||||||
.await
|
.await
|
||||||
.context("failed to rename blobdir")?;
|
.context("failed to rename blobdir")?;
|
||||||
if walfile.exists() {
|
if walfile.exists() {
|
||||||
@@ -229,11 +212,10 @@ impl Accounts {
|
|||||||
Ok(account_config.id)
|
Ok(account_config.id)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
// remove temp account
|
let account_path = std::path::PathBuf::from(&account_config.dir);
|
||||||
fs::remove_dir_all(std::path::PathBuf::from(&account_config.dir))
|
try_many_times(|| fs::remove_dir_all(&account_path))
|
||||||
.await
|
.await
|
||||||
.context("failed to remove account data")?;
|
.context("failed to remove account data")?;
|
||||||
|
|
||||||
self.config.remove_account(account_config.id).await?;
|
self.config.remove_account(account_config.id).await?;
|
||||||
|
|
||||||
// set selection back
|
// set selection back
|
||||||
@@ -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.
|
/// Configuration of a single account.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
struct AccountConfig {
|
struct AccountConfig {
|
||||||
|
|||||||
Reference in New Issue
Block a user