mirror of
https://github.com/chatmail/core.git
synced 2026-05-17 05:46:30 +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
|
- place common headers like `From:` before the large `Autocrypt:` header #3079
|
||||||
- keep track of securejoin joiner status in database to survive restarts #2920
|
- keep track of securejoin joiner status in database to survive restarts #2920
|
||||||
- remove never used `SentboxMove` option #3111
|
- remove never used `SentboxMove` option #3111
|
||||||
- improve speed by caching config values
|
- improve speed by caching config values #3131 #3145
|
||||||
- optimize `markseen_msgs` #3141
|
- optimize `markseen_msgs` #3141
|
||||||
- automatically accept chats with outgoing messages #3143
|
- 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.get_dbfile().display()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
context.sql.config_cache.write().await.clear();
|
||||||
|
|
||||||
let archive = Archive::new(backup_file);
|
let archive = Archive::new(backup_file);
|
||||||
|
|
||||||
let mut entries = archive.entries()?;
|
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]
|
#[test]
|
||||||
fn test_normalize_setup_code() {
|
fn test_normalize_setup_code() {
|
||||||
let norm = normalize_setup_code("123422343234423452346234723482349234");
|
let norm = normalize_setup_code("123422343234423452346234723482349234");
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ pub struct Sql {
|
|||||||
/// open without a passphrase.
|
/// open without a passphrase.
|
||||||
is_encrypted: RwLock<Option<bool>>,
|
is_encrypted: RwLock<Option<bool>>,
|
||||||
|
|
||||||
config_cache: RwLock<HashMap<String, Option<String>>>,
|
pub(crate) config_cache: RwLock<HashMap<String, Option<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sql {
|
impl Sql {
|
||||||
@@ -501,6 +501,7 @@ impl Sql {
|
|||||||
pub async fn set_raw_config(&self, key: impl AsRef<str>, value: Option<&str>) -> Result<()> {
|
pub async fn set_raw_config(&self, key: impl AsRef<str>, value: Option<&str>) -> Result<()> {
|
||||||
let key = key.as_ref();
|
let key = key.as_ref();
|
||||||
|
|
||||||
|
let mut lock = self.config_cache.write().await;
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
let exists = self
|
let exists = self
|
||||||
.exists(
|
.exists(
|
||||||
@@ -526,8 +527,6 @@ impl Sql {
|
|||||||
self.execute("DELETE FROM config WHERE keyname=?;", paramsv![key])
|
self.execute("DELETE FROM config WHERE keyname=?;", paramsv![key])
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut lock = self.config_cache.write().await;
|
|
||||||
lock.insert(key.to_string(), value.map(|s| s.to_string()));
|
lock.insert(key.to_string(), value.map(|s| s.to_string()));
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
@@ -544,6 +543,7 @@ impl Sql {
|
|||||||
return Ok(c);
|
return Ok(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut lock = self.config_cache.write().await;
|
||||||
let value = self
|
let value = self
|
||||||
.query_get_value(
|
.query_get_value(
|
||||||
"SELECT value FROM config WHERE keyname=?;",
|
"SELECT value FROM config WHERE keyname=?;",
|
||||||
@@ -551,8 +551,6 @@ impl Sql {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context(format!("failed to fetch raw config: {}", key.as_ref()))?;
|
.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());
|
lock.insert(key.as_ref().to_string(), value.clone());
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ pub async fn run(context: &Context, sql: &Sql) -> Result<(bool, bool, bool, bool
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let mut lock = context.sql.config_cache.write().await;
|
||||||
|
lock.insert(
|
||||||
|
VERSION_CFG.to_string(),
|
||||||
|
Some(format!("{}", dbversion_before_update)),
|
||||||
|
);
|
||||||
|
drop(lock);
|
||||||
} else {
|
} else {
|
||||||
exists_before_update = true;
|
exists_before_update = true;
|
||||||
dbversion_before_update = sql
|
dbversion_before_update = sql
|
||||||
|
|||||||
Reference in New Issue
Block a user