From 8f4ec79144da7f95c819dd94b41329eab50a8075 Mon Sep 17 00:00:00 2001 From: Carson McManus Date: Mon, 3 Jul 2023 12:25:43 -0400 Subject: [PATCH] parallelize account loading and saving (#273) - parallelize account loading - parallelize account saving --- Cargo.lock | 1 + Cargo.toml | 1 + src/accountmanager.rs | 67 ++++++++++++++++++++++++------------------- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e74e209..b288257 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3078,6 +3078,7 @@ dependencies = [ "proptest", "qrcode", "rand 0.8.5", + "rayon", "regex", "reqwest", "rpassword", diff --git a/Cargo.toml b/Cargo.toml index 7f86d93..55e0556 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ keyring = { version = "2.0.4", optional = true } argon2 = { version = "0.5.0", features = ["std"] } pbkdf2 = { version = "0.12.1", features = ["parallel"] } sha1 = "0.10.5" +rayon = "1.7.0" [dev-dependencies] tempdir = "0.3" diff --git a/src/accountmanager.rs b/src/accountmanager.rs index 48e89b8..1f7a10e 100644 --- a/src/accountmanager.rs +++ b/src/accountmanager.rs @@ -2,6 +2,7 @@ use crate::accountmanager::legacy::SdaManifest; pub use crate::encryption::EncryptionScheme; use crate::encryption::EntryEncryptor; use log::*; +use rayon::prelude::*; use secrecy::{ExposeSecret, SecretString}; use std::collections::HashMap; use std::fs::File; @@ -102,13 +103,14 @@ impl AccountManager { /// Loads all accounts, and registers them. pub fn load_accounts(&mut self) -> anyhow::Result<(), ManifestAccountLoadError> { - let mut accounts = vec![]; - for entry in &self.manifest.entries { - let account = self.load_account_by_entry(entry)?; - accounts.push(account); - } + let accounts = self + .manifest + .entries + .par_iter() + .map(|entry| self.load_account_by_entry(entry)) + .collect::>(); for account in accounts { - self.register_loaded_account(account); + self.register_loaded_account(account?); } Ok(()) } @@ -198,33 +200,40 @@ impl AccountManager { /// Saves the manifest and all loaded accounts. pub fn save(&self) -> anyhow::Result<()> { info!("Saving manifest and accounts..."); - for account in self + let save_results: Vec<_> = self .accounts .values() - .map(|a| a.clone().lock().unwrap().clone()) - { - let entry = self.get_entry(&account.account_name)?.clone(); - debug!("saving {}", entry.filename); - let serialized = serde_json::to_vec(&account)?; - ensure!( - serialized.len() > 2, - "Something extra weird happened and the account was serialized into nothing." - ); + .par_bridge() + .map(|account| -> anyhow::Result<()> { + let account = account.lock().unwrap(); + let entry = self.get_entry(&account.account_name)?.clone(); + debug!("saving {}", entry.filename); + let serialized = serde_json::to_vec(&account.clone())?; + ensure!( + serialized.len() > 2, + "Something extra weird happened and the account was serialized into nothing." + ); - let final_buffer: Vec = match (&self.passkey, entry.encryption.as_ref()) { - (Some(passkey), Some(scheme)) => { - scheme.encrypt(passkey.expose_secret(), serialized)? - } - (None, Some(_)) => { - bail!("maFiles are encrypted, but no passkey was provided."); - } - (_, None) => serialized, - }; + let final_buffer: Vec = match (&self.passkey, entry.encryption.as_ref()) { + (Some(passkey), Some(scheme)) => { + scheme.encrypt(passkey.expose_secret(), serialized)? + } + (None, Some(_)) => { + bail!("maFiles are encrypted, but no passkey was provided."); + } + (_, None) => serialized, + }; - let path = Path::new(&self.folder).join(&entry.filename); - let mut file = File::create(path)?; - file.write_all(final_buffer.as_slice())?; - file.sync_data()?; + let path = Path::new(&self.folder).join(&entry.filename); + let mut file = File::create(path)?; + file.write_all(final_buffer.as_slice())?; + file.sync_data()?; + + Ok(()) + }) + .collect(); + for result in save_results { + result?; } debug!("saving manifest"); let manifest_serialized = serde_json::to_string(&self.manifest)?;