diff --git a/melib/src/backends/maildir/backend.rs b/melib/src/backends/maildir/backend.rs index 024bf36f..88986bb6 100644 --- a/melib/src/backends/maildir/backend.rs +++ b/melib/src/backends/maildir/backend.rs @@ -27,6 +27,7 @@ use crate::error::{MeliError, Result}; use crate::shellexpand::ShellExpandTrait; use futures::prelude::Stream; +use memmap::{Mmap, Protection}; extern crate notify; use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; use std::time::Duration; @@ -277,33 +278,34 @@ impl MailBackend for MaildirType { } (*map).insert(hash, PathBuf::from(&file).into()); } - let op = Box::new(MaildirOp::new(hash, map.clone(), mailbox_hash)); - if let Ok(e) = Envelope::from_token(op, hash) { - mailbox_index.lock().unwrap().insert(e.hash(), mailbox_hash); + if let Ok(mut env) = Envelope::from_bytes( + unsafe { &Mmap::open_path(&file, Protection::Read)?.as_slice() }, + None, + ) { + env.set_hash(hash); + mailbox_index + .lock() + .unwrap() + .insert(env.hash(), mailbox_hash); let file_name = file.strip_prefix(&root_path).unwrap().to_path_buf(); if let Ok(cached) = cache_dir.place_cache_file(file_name) { /* place result in cache directory */ - let f = match fs::File::create(cached) { - Ok(f) => f, - Err(e) => { - panic!("{}", e); - } - }; - let metadata = f.metadata().unwrap(); + let f = fs::File::create(cached)?; + let metadata = f.metadata()?; let mut permissions = metadata.permissions(); permissions.set_mode(0o600); // Read/write for owner only. - f.set_permissions(permissions).unwrap(); + f.set_permissions(permissions)?; let writer = io::BufWriter::new(f); - bincode::serialize_into(writer, &e).unwrap(); + bincode::serialize_into(writer, &env)?; } (sender)( account_hash, BackendEvent::Refresh(RefreshEvent { account_hash, mailbox_hash, - kind: Create(Box::new(e)), + kind: Create(Box::new(env)), }), ); } else { @@ -402,7 +404,7 @@ impl MailBackend for MaildirType { .strip_prefix(&root_path) .unwrap() .to_path_buf(); - if let Some(env) = add_path_to_index( + if let Ok(env) = add_path_to_index( &hash_indexes, mailbox_hash, pathbuf.as_path(), @@ -457,7 +459,7 @@ impl MailBackend for MaildirType { drop(hash_indexes_lock); /* Did we just miss a Create event? In any case, create * envelope. */ - if let Some(env) = add_path_to_index( + if let Ok(env) = add_path_to_index( &hash_indexes, mailbox_hash, pathbuf.as_path(), @@ -483,12 +485,13 @@ impl MailBackend for MaildirType { let new_hash: EnvelopeHash = get_file_hash(pathbuf.as_path()); if index_lock.get_mut(&new_hash).is_none() { debug!("write notice"); - let op = Box::new(MaildirOp::new( - new_hash, - hash_indexes.clone(), - mailbox_hash, - )); - if let Ok(env) = Envelope::from_token(op, new_hash) { + if let Ok(mut env) = Envelope::from_bytes( + unsafe { + &Mmap::open_path(&pathbuf, Protection::Read)?.as_slice() + }, + None, + ) { + env.set_hash(new_hash); debug!("{}\t{:?}", new_hash, &pathbuf); debug!( "hash {}, path: {:?} couldn't be parsed", @@ -636,7 +639,7 @@ impl MailBackend for MaildirType { .to_path_buf(); debug!("filename = {:?}", file_name); drop(hash_indexes_lock); - if let Some(env) = add_path_to_index( + if let Ok(env) = add_path_to_index( &hash_indexes, mailbox_hash, dest.as_path(), @@ -1048,193 +1051,6 @@ impl MaildirType { })) } - /* - pub fn multicore( - &mut self, - cores: usize, - mailbox_hash: MailboxHash, - ) -> Async>> { - let mut w = AsyncBuilder::new(); - let cache_dir = xdg::BaseDirectories::with_profile("meli", &self.name).unwrap(); - - let handle = { - let tx = w.tx(); - let mailbox: &MaildirMailbox = &self.mailboxes[&mailbox_hash]; - let unseen = mailbox.unseen.clone(); - let total = mailbox.total.clone(); - let tx_final = w.tx(); - let mut path: PathBuf = mailbox.fs_path().into(); - let name = format!("parsing {:?}", mailbox.name()); - let root_path = self.path.to_path_buf(); - let map = self.hash_indexes.clone(); - let mailbox_index = self.mailbox_index.clone(); - - let closure = move |work_context: crate::async_workers::WorkContext| { - work_context - .set_name - .send((std::thread::current().id(), name.clone())) - .unwrap(); - let mut thunk = move || { - path.push("new"); - for d in path.read_dir()? { - if let Ok(p) = d { - move_to_cur(p.path()).ok().take(); - } - } - path.pop(); - - path.push("cur"); - let iter = path.read_dir()?; - let count = path.read_dir()?.count(); - let mut files: Vec = Vec::with_capacity(count); - let mut ret = Vec::with_capacity(count); - for e in iter { - let e = e.and_then(|x| { - let path = x.path(); - Ok(path) - })?; - files.push(e); - } - if !files.is_empty() { - crossbeam::scope(|scope| { - let mut threads = Vec::with_capacity(cores); - let chunk_size = if count / cores > 0 { - count / cores - } else { - count - }; - for chunk in files.chunks(chunk_size) { - let unseen = unseen.clone(); - let total = total.clone(); - let cache_dir = cache_dir.clone(); - let tx = tx.clone(); - let map = map.clone(); - let mailbox_index = mailbox_index.clone(); - let root_path = root_path.clone(); - let s = scope.builder().name(name.clone()).spawn(move |_| { - let len = chunk.len(); - let size = if len <= 100 { 100 } else { (len / 100) * 100 }; - let mut local_r: Vec = - Vec::with_capacity(chunk.len()); - for c in chunk.chunks(size) { - //thread::yield_now(); - let map = map.clone(); - let mailbox_index = mailbox_index.clone(); - let len = c.len(); - for file in c { - /* Check if we have a cache file with this email's - * filename */ - let file_name = PathBuf::from(file) - .strip_prefix(&root_path) - .unwrap() - .to_path_buf(); - if let Some(cached) = - cache_dir.find_cache_file(&file_name) - { - /* Cached struct exists, try to load it */ - let reader = io::BufReader::new( - fs::File::open(&cached).unwrap(), - ); - let result: result::Result = - bincode::deserialize_from(reader); - if let Ok(env) = result { - let mut map = map.lock().unwrap(); - let map = map.entry(mailbox_hash).or_default(); - let hash = env.hash(); - map.insert(hash, file.clone().into()); - mailbox_index - .lock() - .unwrap() - .insert(hash, mailbox_hash); - if !env.is_seen() { - *unseen.lock().unwrap() += 1; - } - *total.lock().unwrap() += 1; - local_r.push(env); - continue; - } - }; - let hash = get_file_hash(file); - { - let mut map = map.lock().unwrap(); - let map = map.entry(mailbox_hash).or_default(); - (*map).insert(hash, PathBuf::from(file).into()); - } - let op = Box::new(MaildirOp::new( - hash, - map.clone(), - mailbox_hash, - )); - if let Ok(e) = Envelope::from_token(op, hash) { - mailbox_index - .lock() - .unwrap() - .insert(e.hash(), mailbox_hash); - if let Ok(cached) = - cache_dir.place_cache_file(file_name) - { - /* place result in cache directory */ - let f = match fs::File::create(cached) { - Ok(f) => f, - Err(e) => { - panic!("{}", e); - } - }; - let metadata = f.metadata().unwrap(); - let mut permissions = metadata.permissions(); - - permissions.set_mode(0o600); // Read/write for owner only. - f.set_permissions(permissions).unwrap(); - - let writer = io::BufWriter::new(f); - bincode::serialize_into(writer, &e).unwrap(); - } - if !e.is_seen() { - *unseen.lock().unwrap() += 1; - } - *total.lock().unwrap() += 1; - local_r.push(e); - } else { - debug!( - "DEBUG: hash {}, path: {} couldn't be parsed", - hash, - file.as_path().display() - ); - continue; - } - } - tx.send(AsyncStatus::ProgressReport(len)).unwrap(); - } - local_r - }); - threads.push(s.unwrap()); - } - for t in threads { - let mut result = t.join().unwrap(); - ret.append(&mut result); - work_context - .set_status - .send(( - std::thread::current().id(), - format!("parsing.. {}/{}", ret.len(), files.len()), - )) - .unwrap(); - } - }) - .unwrap(); - } - Ok(ret) - }; - let result = thunk(); - tx_final.send(AsyncStatus::Payload(result)).unwrap(); - tx_final.send(AsyncStatus::Finished).unwrap(); - }; - Box::new(closure) - }; - w.build(handle) - } - */ - pub fn save_to_mailbox(mut path: PathBuf, bytes: Vec, flags: Option) -> Result<()> { for d in &["cur", "new", "tmp"] { path.push(d); @@ -1330,49 +1146,42 @@ fn add_path_to_index( path: &Path, cache_dir: &xdg::BaseDirectories, file_name: PathBuf, -) -> Option { - let env: Envelope; +) -> Result { debug!("add_path_to_index path {:?} filename{:?}", path, file_name); - let hash = get_file_hash(path); + let env_hash = get_file_hash(path); { let mut map = hash_index.lock().unwrap(); let map = map.entry(mailbox_hash).or_default(); - map.insert(hash, path.to_path_buf().into()); + map.insert(env_hash, path.to_path_buf().into()); debug!( "inserted {} in {} map, len={}", - hash, + env_hash, mailbox_hash, map.len() ); } - let op = Box::new(MaildirOp::new(hash, hash_index.clone(), mailbox_hash)); - if let Ok(e) = Envelope::from_token(op, hash) { - debug!("add_path_to_index gen {}\t{}", hash, file_name.display()); - if let Ok(cached) = cache_dir.place_cache_file(file_name) { - debug!("putting in cache"); - /* place result in cache directory */ - let f = match fs::File::create(cached) { - Ok(f) => f, - Err(e) => { - panic!("{}", e); - } - }; - let metadata = f.metadata().unwrap(); - let mut permissions = metadata.permissions(); + //Mmap::open_path(self.path(), Protection::Read)? + let mut env = Envelope::from_bytes( + unsafe { &Mmap::open_path(path, Protection::Read)?.as_slice() }, + None, + )?; + env.set_hash(env_hash); + debug!( + "add_path_to_index gen {}\t{}", + env_hash, + file_name.display() + ); + if let Ok(cached) = cache_dir.place_cache_file(file_name) { + debug!("putting in cache"); + /* place result in cache directory */ + let f = fs::File::create(cached)?; + let metadata = f.metadata()?; + let mut permissions = metadata.permissions(); - permissions.set_mode(0o600); // Read/write for owner only. - f.set_permissions(permissions).unwrap(); - let writer = io::BufWriter::new(f); - bincode::serialize_into(writer, &e).unwrap(); - } - env = e; - } else { - debug!( - "DEBUG: hash {}, path: {} couldn't be parsed in `add_path_to_index`", - hash, - path.display() - ); - return None; + permissions.set_mode(0o600); // Read/write for owner only. + f.set_permissions(permissions)?; + let writer = io::BufWriter::new(f); + bincode::serialize_into(writer, &env)?; } - Some(env) + Ok(env) } diff --git a/melib/src/backends/maildir/stream.rs b/melib/src/backends/maildir/stream.rs index 7fe9f98c..56ee61cd 100644 --- a/melib/src/backends/maildir/stream.rs +++ b/melib/src/backends/maildir/stream.rs @@ -25,6 +25,7 @@ use core::future::Future; use core::pin::Pin; use futures::stream::{FuturesUnordered, StreamExt}; use futures::task::{Context, Poll}; +use memmap::{Mmap, Protection}; use std::io::{self}; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; @@ -32,7 +33,11 @@ use std::result; use std::sync::{Arc, Mutex}; pub struct MaildirStream { - payloads: Pin>> + Send + 'static>>>>>, + payloads: Pin< + Box< + FuturesUnordered>> + Send + 'static>>>, + >, + >, } impl MaildirStream { @@ -135,44 +140,46 @@ impl MaildirStream { continue; } }; - let hash = get_file_hash(file); + let env_hash = get_file_hash(file); { let mut map = map.lock().unwrap(); let map = map.entry(mailbox_hash).or_default(); - (*map).insert(hash, PathBuf::from(file).into()); + (*map).insert(env_hash, PathBuf::from(file).into()); } - let op = Box::new(MaildirOp::new(hash, map.clone(), mailbox_hash)); - if let Ok(e) = Envelope::from_token(op, hash) { - mailbox_index.lock().unwrap().insert(e.hash(), mailbox_hash); - if let Ok(cached) = cache_dir.place_cache_file(file_name) { - /* place result in cache directory */ - let f = match fs::File::create(cached) { - Ok(f) => f, - Err(e) => { - panic!("{}", e); - } - }; - let metadata = f.metadata().unwrap(); - let mut permissions = metadata.permissions(); + match Envelope::from_bytes( + unsafe { &Mmap::open_path(&file, Protection::Read)?.as_slice() }, + None, + ) { + Ok(mut env) => { + env.set_hash(env_hash); + mailbox_index.lock().unwrap().insert(env_hash, mailbox_hash); + if let Ok(cached) = cache_dir.place_cache_file(file_name) { + /* place result in cache directory */ + let f = fs::File::create(cached)?; + let metadata = f.metadata()?; + let mut permissions = metadata.permissions(); - permissions.set_mode(0o600); // Read/write for owner only. - f.set_permissions(permissions).unwrap(); + permissions.set_mode(0o600); // Read/write for owner only. + f.set_permissions(permissions)?; - let writer = io::BufWriter::new(f); - bincode::serialize_into(writer, &e).unwrap(); + let writer = io::BufWriter::new(f); + bincode::serialize_into(writer, &env)?; + } + if !env.is_seen() { + *unseen.lock().unwrap() += 1; + } + *total.lock().unwrap() += 1; + local_r.push(env); } - if !e.is_seen() { - *unseen.lock().unwrap() += 1; + Err(err) => { + debug!( + "DEBUG: hash {}, path: {} couldn't be parsed, {}", + env_hash, + file.as_path().display(), + err, + ); + continue; } - *total.lock().unwrap() += 1; - local_r.push(e); - } else { - debug!( - "DEBUG: hash {}, path: {} couldn't be parsed", - hash, - file.as_path().display() - ); - continue; } } } diff --git a/melib/src/email.rs b/melib/src/email.rs index f3412962..00ae9bc9 100644 --- a/melib/src/email.rs +++ b/melib/src/email.rs @@ -41,7 +41,6 @@ mod headers; pub mod signatures; pub use headers::*; -use crate::backends::BackendOp; use crate::datetime::UnixTimestamp; use crate::error::{MeliError, Result}; use crate::thread::ThreadNodeHash; @@ -217,14 +216,6 @@ impl Envelope { Err(MeliError::new("Couldn't parse mail.")) } - pub fn from_token(mut operation: Box, hash: EnvelopeHash) -> Result { - let mut e = Envelope::new(hash); - e.flags = futures::executor::block_on(operation.fetch_flags()?)?; - let bytes = futures::executor::block_on(operation.as_bytes()?)?; - e.populate_headers(&bytes)?; - Ok(e) - } - pub fn hash(&self) -> EnvelopeHash { self.hash } @@ -487,13 +478,6 @@ impl Envelope { }) } - /// Requests bytes from backend and thus can fail - pub fn body(&self, mut operation: Box) -> Result { - debug!("searching body for {:?}", self.message_id_display()); - let bytes = futures::executor::block_on(operation.as_bytes()?)?; - Ok(self.body_bytes(&bytes)) - } - pub fn subject(&self) -> Cow { match self.subject { Some(ref s) => Cow::from(s), diff --git a/melib/src/error.rs b/melib/src/error.rs index 5976afd4..5e4c925e 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -269,6 +269,13 @@ impl From for MeliError { } } +impl From> for MeliError { + #[inline] + fn from(kind: Box) -> MeliError { + MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) + } +} + impl From for MeliError { #[inline] fn from(kind: nix::Error) -> MeliError { diff --git a/src/conf/accounts.rs b/src/conf/accounts.rs index 5b888114..576c08f2 100644 --- a/src/conf/accounts.rs +++ b/src/conf/accounts.rs @@ -606,47 +606,98 @@ impl Account { RefreshEventKind::Update(old_hash, envelope) => { #[cfg(feature = "sqlite3")] { - if let Err(err) = crate::sqlite3::remove(old_hash).and_then(|_| { - crate::sqlite3::insert(&envelope, &self.backend, &self.name) + match crate::sqlite3::remove(old_hash).map(|_| { + crate::sqlite3::insert( + (*envelope).clone(), + self.backend.clone(), + self.name.clone(), + ) }) { - melib::log( - format!( - "Failed to update envelope {} in cache: {}", - envelope.message_id_display(), - err.to_string() - ), - melib::ERROR, - ); + Err(err) => { + melib::log( + format!( + "Failed to update envelope {} in cache: {}", + envelope.message_id_display(), + err.to_string() + ), + melib::ERROR, + ); + } + Ok(job) => { + let (channel, handle, job_id) = + self.job_executor.spawn_blocking(job); + self.insert_job( + job_id, + JobRequest::Generic { + name: format!( + "Update envelope {} in sqlite3 cache", + envelope.message_id_display() + ) + .into(), + handle, + channel, + on_finish: None, + }, + ); + } } } self.collection.update(old_hash, *envelope, mailbox_hash); return Some(EnvelopeUpdate(old_hash)); } RefreshEventKind::NewFlags(env_hash, (flags, tags)) => { - let mut envelopes = self.collection.envelopes.write().unwrap(); - envelopes.entry(env_hash).and_modify(|entry| { - entry.labels_mut().clear(); - entry - .labels_mut() - .extend(tags.into_iter().map(|h| tag_hash!(h))); - entry.set_flags(flags); - }); + self.collection + .envelopes + .write() + .unwrap() + .entry(env_hash) + .and_modify(|entry| { + entry.labels_mut().clear(); + entry + .labels_mut() + .extend(tags.into_iter().map(|h| tag_hash!(h))); + entry.set_flags(flags); + }); #[cfg(feature = "sqlite3")] { - if let Err(err) = crate::sqlite3::remove(env_hash).and_then(|_| { - crate::sqlite3::insert(&envelopes[&env_hash], &self.backend, &self.name) + match crate::sqlite3::remove(env_hash).map(|_| { + crate::sqlite3::insert( + self.collection.envelopes.read().unwrap()[&env_hash].clone(), + self.backend.clone(), + self.name.clone(), + ) }) { - melib::log( - format!( - "Failed to update envelope {} in cache: {}", - envelopes[&env_hash].message_id_display(), - err.to_string() - ), - melib::ERROR, - ); + Ok(job) => { + let (channel, handle, job_id) = + self.job_executor.spawn_blocking(job); + self.insert_job( + job_id, + JobRequest::Generic { + name: format!( + "Update envelope {} in sqlite3 cache", + self.collection.envelopes.read().unwrap()[&env_hash] + .message_id_display() + ) + .into(), + handle, + channel, + on_finish: None, + }, + ); + } + Err(err) => { + melib::log( + format!( + "Failed to update envelope {} in cache: {}", + self.collection.envelopes.read().unwrap()[&env_hash] + .message_id_display(), + err.to_string() + ), + melib::ERROR, + ); + } } } - drop(envelopes); self.collection.update_flags(env_hash, mailbox_hash); return Some(EnvelopeUpdate(env_hash)); } @@ -657,19 +708,42 @@ impl Account { } #[cfg(feature = "sqlite3")] { - let envelopes = self.collection.envelopes.read(); - let envelopes = envelopes.unwrap(); - if let Err(err) = crate::sqlite3::remove(old_hash).and_then(|_| { - crate::sqlite3::insert(&envelopes[&new_hash], &self.backend, &self.name) + match crate::sqlite3::remove(old_hash).map(|_| { + crate::sqlite3::insert( + self.collection.envelopes.read().unwrap()[&new_hash].clone(), + self.backend.clone(), + self.name.clone(), + ) }) { - melib::log( - format!( - "Failed to update envelope {} in cache: {}", - &envelopes[&new_hash].message_id_display(), - err.to_string() - ), - melib::ERROR, - ); + Err(err) => { + melib::log( + format!( + "Failed to update envelope {} in cache: {}", + &self.collection.envelopes.read().unwrap()[&new_hash] + .message_id_display(), + err.to_string() + ), + melib::ERROR, + ); + } + Ok(job) => { + let (channel, handle, job_id) = + self.job_executor.spawn_blocking(job); + self.insert_job( + job_id, + JobRequest::Generic { + name: format!( + "Update envelope {} in sqlite3 cache", + self.collection.envelopes.read().unwrap()[&new_hash] + .message_id_display() + ) + .into(), + handle, + channel, + on_finish: None, + }, + ); + } } } return Some(EnvelopeRename(old_hash, new_hash)); @@ -694,18 +768,25 @@ impl Account { }; #[cfg(feature = "sqlite3")] { - if let Err(err) = - crate::sqlite3::insert(&envelope, &self.backend, &self.name) - { - melib::log( - format!( - "Failed to insert envelope {} in cache: {}", - envelope.message_id_display(), - err.to_string() - ), - melib::ERROR, - ); - } + let (channel, handle, job_id) = + self.job_executor.spawn_blocking(crate::sqlite3::insert( + (*envelope).clone(), + self.backend.clone(), + self.name.clone(), + )); + self.insert_job( + job_id, + JobRequest::Generic { + name: format!( + "Update envelope {} in sqlite3 cache", + envelope.message_id_display() + ) + .into(), + handle, + channel, + on_finish: None, + }, + ); } if self.collection.insert(*envelope, mailbox_hash) { diff --git a/src/sqlite3.rs b/src/sqlite3.rs index be06b466..8bd5967d 100644 --- a/src/sqlite3.rs +++ b/src/sqlite3.rs @@ -140,10 +140,10 @@ pub fn db_path() -> Result { //} // // -pub fn insert( - envelope: &Envelope, - backend: &Arc>>, - acc_name: &str, +pub async fn insert( + envelope: Envelope, + backend: Arc>>, + acc_name: String, ) -> Result<()> { let db_path = db_path()?; if !db_path.exists() { @@ -153,11 +153,14 @@ pub fn insert( } let conn = melib_sqlite3::open_db(db_path)?; - let backend_lck = backend.read().unwrap(); - let body = match backend_lck - .operation(envelope.hash()) - .and_then(|op| envelope.body(op)) - { + + let op = backend + .read() + .unwrap() + .operation(envelope.hash())? + .as_bytes()?; + + let body = match op.await.map(|bytes| envelope.body_bytes(&bytes)) { Ok(body) => body.text(), Err(err) => { debug!( @@ -314,25 +317,21 @@ pub fn index(context: &mut crate::state::Context, account_index: usize) -> Resul ); for chunk in env_hashes.chunks(200) { ctr += chunk.len(); - let envelopes_lck = acc_mutex.read().unwrap(); - let backend_lck = backend_mutex.read().unwrap(); for env_hash in chunk { + let mut op = backend_mutex.read().unwrap().operation(*env_hash)?; + let bytes = op + .as_bytes()? + .await + .chain_err_summary(|| format!("Failed to open envelope {}", env_hash))?; + let envelopes_lck = acc_mutex.read().unwrap(); if let Some(e) = envelopes_lck.get(&env_hash) { - let body = backend_lck - .operation(e.hash()) - .and_then(|op| e.body(op)) - .chain_err_summary(|| { - format!("Failed to open envelope {}", e.message_id_display(),) - })? - .text() - .replace('\0', ""); + let body = e.body_bytes(&bytes).text().replace('\0', ""); conn.execute("INSERT OR REPLACE INTO envelopes (account_id, hash, date, _from, _to, cc, bcc, subject, message_id, in_reply_to, _references, flags, has_attachments, body_text, timestamp) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15)", params![account_id, e.hash().to_be_bytes().to_vec(), e.date_as_str(), e.field_from_to_string(), e.field_to_to_string(), e.field_cc_to_string(), e.field_bcc_to_string(), e.subject().into_owned().trim_end_matches('\u{0}'), e.message_id_display().to_string(), e.in_reply_to_display().map(|f| f.to_string()).unwrap_or(String::new()), e.field_references_to_string(), i64::from(e.flags().bits()), if e.has_attachments() { 1 } else { 0 }, body, e.date().to_be_bytes().to_vec()], ).chain_err_summary(|| format!( "Failed to insert envelope {}", e.message_id_display()))?; } } - drop(envelopes_lck); let sleep_dur = std::time::Duration::from_millis(20); std::thread::sleep(sleep_dur); }