mirror of
https://github.com/chatmail/core.git
synced 2026-04-28 02:46:29 +03:00
config_cache fixes (#3145)
* add simple backup export/import test this test fails on current master until the context is recrated. * avoid config_cache races adds needed SQL-statements to config_cache locking. otherwise, another thread may alter the database eg. between SELECT and the config_cache update - resulting in the wrong value being written to config_cache. * also update config_cache on initializing tables VERSION_CFG is also set later, however, not doing it here will result in bugs when we change DBVERSION at some point. as this alters only VERSION_CFG and that is executed sequentially anyway, race conditions between SQL and config_cache seems not to be an issue in this case. * clear config_cache after backup import import replaces the whole database, so config_cache needs to be invalidated as well. we do that before import, so in case a backup is imported only partly, the cache does not add additional problems. * update CHANGELOG
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
- place common headers like `From:` before the large `Autocrypt:` header #3079
|
||||
- keep track of securejoin joiner status in database to survive restarts #2920
|
||||
- remove never used `SentboxMove` option #3111
|
||||
- improve speed by caching config values
|
||||
- improve speed by caching config values #3131 #3145
|
||||
- optimize `markseen_msgs` #3141
|
||||
- automatically accept chats with outgoing messages #3143
|
||||
|
||||
|
||||
50
src/imex.rs
50
src/imex.rs
@@ -460,6 +460,8 @@ async fn import_backup(
|
||||
context.get_dbfile().display()
|
||||
);
|
||||
|
||||
context.sql.config_cache.write().await.clear();
|
||||
|
||||
let archive = Archive::new(backup_file);
|
||||
|
||||
let mut entries = archive.entries()?;
|
||||
@@ -901,6 +903,54 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_export_and_import_backup() -> Result<()> {
|
||||
let backup_dir = tempfile::tempdir().unwrap();
|
||||
|
||||
let context1 = TestContext::new_alice().await;
|
||||
assert!(context1.is_configured().await?);
|
||||
|
||||
let context2 = TestContext::new().await;
|
||||
assert!(!context2.is_configured().await?);
|
||||
assert!(has_backup(&context2, backup_dir.path().as_ref())
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
// export from context1
|
||||
assert!(imex(
|
||||
&context1,
|
||||
ImexMode::ExportBackup,
|
||||
backup_dir.path().as_ref(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.is_ok());
|
||||
let _event = context1
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
|
||||
.await;
|
||||
|
||||
// import to context2
|
||||
let backup = has_backup(&context2, backup_dir.path().as_ref()).await?;
|
||||
assert!(
|
||||
imex(&context2, ImexMode::ImportBackup, backup.as_ref(), None)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
let _event = context2
|
||||
.evtracker
|
||||
.get_matching(|evt| matches!(evt, EventType::ImexProgress(1000)))
|
||||
.await;
|
||||
|
||||
assert!(context2.is_configured().await?);
|
||||
assert_eq!(
|
||||
context2.get_config(Config::Addr).await?,
|
||||
Some("alice@example.org".to_string())
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normalize_setup_code() {
|
||||
let norm = normalize_setup_code("123422343234423452346234723482349234");
|
||||
|
||||
@@ -48,7 +48,7 @@ pub struct Sql {
|
||||
/// open without a passphrase.
|
||||
is_encrypted: RwLock<Option<bool>>,
|
||||
|
||||
config_cache: RwLock<HashMap<String, Option<String>>>,
|
||||
pub(crate) config_cache: RwLock<HashMap<String, Option<String>>>,
|
||||
}
|
||||
|
||||
impl Sql {
|
||||
@@ -501,6 +501,7 @@ impl Sql {
|
||||
pub async fn set_raw_config(&self, key: impl AsRef<str>, value: Option<&str>) -> Result<()> {
|
||||
let key = key.as_ref();
|
||||
|
||||
let mut lock = self.config_cache.write().await;
|
||||
if let Some(value) = value {
|
||||
let exists = self
|
||||
.exists(
|
||||
@@ -526,8 +527,6 @@ impl Sql {
|
||||
self.execute("DELETE FROM config WHERE keyname=?;", paramsv![key])
|
||||
.await?;
|
||||
}
|
||||
|
||||
let mut lock = self.config_cache.write().await;
|
||||
lock.insert(key.to_string(), value.map(|s| s.to_string()));
|
||||
drop(lock);
|
||||
|
||||
@@ -544,6 +543,7 @@ impl Sql {
|
||||
return Ok(c);
|
||||
}
|
||||
|
||||
let mut lock = self.config_cache.write().await;
|
||||
let value = self
|
||||
.query_get_value(
|
||||
"SELECT value FROM config WHERE keyname=?;",
|
||||
@@ -551,8 +551,6 @@ impl Sql {
|
||||
)
|
||||
.await
|
||||
.context(format!("failed to fetch raw config: {}", key.as_ref()))?;
|
||||
|
||||
let mut lock = self.config_cache.write().await;
|
||||
lock.insert(key.as_ref().to_string(), value.clone());
|
||||
drop(lock);
|
||||
|
||||
|
||||
@@ -36,6 +36,13 @@ pub async fn run(context: &Context, sql: &Sql) -> Result<(bool, bool, bool, bool
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
|
||||
let mut lock = context.sql.config_cache.write().await;
|
||||
lock.insert(
|
||||
VERSION_CFG.to_string(),
|
||||
Some(format!("{}", dbversion_before_update)),
|
||||
);
|
||||
drop(lock);
|
||||
} else {
|
||||
exists_before_update = true;
|
||||
dbversion_before_update = sql
|
||||
|
||||
Reference in New Issue
Block a user