parallelize account loading and saving (#273)

- parallelize account loading
- parallelize account saving
This commit is contained in:
Carson McManus 2023-07-03 12:25:43 -04:00 committed by GitHub
parent 969baeed4c
commit 8f4ec79144
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 29 deletions

1
Cargo.lock generated
View file

@ -3078,6 +3078,7 @@ dependencies = [
"proptest", "proptest",
"qrcode", "qrcode",
"rand 0.8.5", "rand 0.8.5",
"rayon",
"regex", "regex",
"reqwest", "reqwest",
"rpassword", "rpassword",

View file

@ -67,6 +67,7 @@ keyring = { version = "2.0.4", optional = true }
argon2 = { version = "0.5.0", features = ["std"] } argon2 = { version = "0.5.0", features = ["std"] }
pbkdf2 = { version = "0.12.1", features = ["parallel"] } pbkdf2 = { version = "0.12.1", features = ["parallel"] }
sha1 = "0.10.5" sha1 = "0.10.5"
rayon = "1.7.0"
[dev-dependencies] [dev-dependencies]
tempdir = "0.3" tempdir = "0.3"

View file

@ -2,6 +2,7 @@ use crate::accountmanager::legacy::SdaManifest;
pub use crate::encryption::EncryptionScheme; pub use crate::encryption::EncryptionScheme;
use crate::encryption::EntryEncryptor; use crate::encryption::EntryEncryptor;
use log::*; use log::*;
use rayon::prelude::*;
use secrecy::{ExposeSecret, SecretString}; use secrecy::{ExposeSecret, SecretString};
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
@ -102,13 +103,14 @@ impl AccountManager {
/// Loads all accounts, and registers them. /// Loads all accounts, and registers them.
pub fn load_accounts(&mut self) -> anyhow::Result<(), ManifestAccountLoadError> { pub fn load_accounts(&mut self) -> anyhow::Result<(), ManifestAccountLoadError> {
let mut accounts = vec![]; let accounts = self
for entry in &self.manifest.entries { .manifest
let account = self.load_account_by_entry(entry)?; .entries
accounts.push(account); .par_iter()
} .map(|entry| self.load_account_by_entry(entry))
.collect::<Vec<_>>();
for account in accounts { for account in accounts {
self.register_loaded_account(account); self.register_loaded_account(account?);
} }
Ok(()) Ok(())
} }
@ -198,33 +200,40 @@ impl AccountManager {
/// Saves the manifest and all loaded accounts. /// Saves the manifest and all loaded accounts.
pub fn save(&self) -> anyhow::Result<()> { pub fn save(&self) -> anyhow::Result<()> {
info!("Saving manifest and accounts..."); info!("Saving manifest and accounts...");
for account in self let save_results: Vec<_> = self
.accounts .accounts
.values() .values()
.map(|a| a.clone().lock().unwrap().clone()) .par_bridge()
{ .map(|account| -> anyhow::Result<()> {
let entry = self.get_entry(&account.account_name)?.clone(); let account = account.lock().unwrap();
debug!("saving {}", entry.filename); let entry = self.get_entry(&account.account_name)?.clone();
let serialized = serde_json::to_vec(&account)?; debug!("saving {}", entry.filename);
ensure!( let serialized = serde_json::to_vec(&account.clone())?;
serialized.len() > 2, ensure!(
"Something extra weird happened and the account was serialized into nothing." serialized.len() > 2,
); "Something extra weird happened and the account was serialized into nothing."
);
let final_buffer: Vec<u8> = match (&self.passkey, entry.encryption.as_ref()) { let final_buffer: Vec<u8> = match (&self.passkey, entry.encryption.as_ref()) {
(Some(passkey), Some(scheme)) => { (Some(passkey), Some(scheme)) => {
scheme.encrypt(passkey.expose_secret(), serialized)? scheme.encrypt(passkey.expose_secret(), serialized)?
} }
(None, Some(_)) => { (None, Some(_)) => {
bail!("maFiles are encrypted, but no passkey was provided."); bail!("maFiles are encrypted, but no passkey was provided.");
} }
(_, None) => serialized, (_, None) => serialized,
}; };
let path = Path::new(&self.folder).join(&entry.filename); let path = Path::new(&self.folder).join(&entry.filename);
let mut file = File::create(path)?; let mut file = File::create(path)?;
file.write_all(final_buffer.as_slice())?; file.write_all(final_buffer.as_slice())?;
file.sync_data()?; file.sync_data()?;
Ok(())
})
.collect();
for result in save_results {
result?;
} }
debug!("saving manifest"); debug!("saving manifest");
let manifest_serialized = serde_json::to_string(&self.manifest)?; let manifest_serialized = serde_json::to_string(&self.manifest)?;