diff --git a/CHANGELOG.md b/CHANGELOG.md index e2b168fbd..344482d18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,8 +19,10 @@ - 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 - optimize `markseen_msgs` #3141 + ### Fixes - Fix a bug where sometimes the file extension of a long filename containing a dot was cropped #3098 diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index 92e95d461..72f3d23ac 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -84,6 +84,7 @@ async fn reset_tables(context: &Context, bits: i32) { ) .await .unwrap(); + context.sql().config_cache().write().await.clear(); context .sql() .execute("DELETE FROM leftgrps;", paramsv![]) diff --git a/src/sql.rs b/src/sql.rs index d44b9db5d..59c449010 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -3,7 +3,7 @@ use async_std::path::Path; use async_std::sync::RwLock; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; use std::time::Duration; @@ -47,6 +47,8 @@ pub struct Sql { /// None if the database is not open, true if it is open with passphrase and false if it is /// open without a passphrase. is_encrypted: RwLock>, + + config_cache: RwLock>>, } impl Sql { @@ -55,6 +57,7 @@ impl Sql { dbfile, pool: Default::default(), is_encrypted: Default::default(), + config_cache: Default::default(), } } @@ -497,6 +500,7 @@ impl Sql { /// will already have been logged. pub async fn set_raw_config(&self, key: impl AsRef, value: Option<&str>) -> Result<()> { let key = key.as_ref(); + if let Some(value) = value { let exists = self .exists( @@ -523,11 +527,23 @@ impl Sql { .await?; } + let mut lock = self.config_cache.write().await; + lock.insert(key.to_string(), value.map(|s| s.to_string())); + drop(lock); + Ok(()) } /// Get configuration options from the database. pub async fn get_raw_config(&self, key: impl AsRef) -> Result> { + let lock = self.config_cache.read().await; + let cached = lock.get(key.as_ref()).cloned(); + drop(lock); + + if let Some(c) = cached { + return Ok(c); + } + let value = self .query_get_value( "SELECT value FROM config WHERE keyname=?;", @@ -536,6 +552,10 @@ 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); + Ok(value) } @@ -573,6 +593,11 @@ impl Sql { .await .map(|s| s.and_then(|r| r.parse().ok())) } + + #[cfg(feature = "internals")] + pub fn config_cache(&self) -> &RwLock>> { + &self.config_cache + } } pub async fn housekeeping(context: &Context) -> Result<()> { diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index aa7500708..c060bbbae 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -622,6 +622,10 @@ impl Sql { .await .with_context(|| format!("execute_migration failed for version {}", version))?; + let mut lock = self.config_cache.write().await; + lock.insert(VERSION_CFG.to_string(), Some(format!("{}", version))); + drop(lock); + Ok(()) } }