melib/backends: add collection() method to MailBackend

Keep track of the Collection state in the backend side
lazy_fetch
Manos Pitsidianakis 2020-08-10 14:24:21 +03:00
parent eb8d29813c
commit 781a1d0e1b
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
19 changed files with 110 additions and 91 deletions

View File

@ -58,7 +58,7 @@ use self::maildir::MaildirType;
use self::mbox::MboxType; use self::mbox::MboxType;
use super::email::{Envelope, EnvelopeHash, Flag}; use super::email::{Envelope, EnvelopeHash, Flag};
use std::any::Any; use std::any::Any;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::BTreeSet;
use std::fmt; use std::fmt;
use std::fmt::Debug; use std::fmt::Debug;
use std::ops::Deref; use std::ops::Deref;
@ -348,9 +348,7 @@ pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
mailbox_hash: MailboxHash, mailbox_hash: MailboxHash,
) -> ResultFuture<()>; ) -> ResultFuture<()>;
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn collection(&self) -> crate::Collection;
None
}
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any;

View File

@ -42,20 +42,21 @@ use crate::backends::{
*, *,
}; };
use crate::collection::Collection;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::connections::timeout; use crate::connections::timeout;
use crate::email::{parser::BytesExt, *}; use crate::email::{parser::BytesExt, *};
use crate::error::{MeliError, Result, ResultIntoMeliError}; use crate::error::{MeliError, Result, ResultIntoMeliError};
use futures::lock::Mutex as FutureMutex; use futures::lock::Mutex as FutureMutex;
use futures::stream::Stream; use futures::stream::Stream;
use std::collections::{hash_map::DefaultHasher, BTreeMap}; use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeSet, HashMap, HashSet}; use std::collections::{BTreeSet, HashMap, HashSet};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::convert::TryInto; use std::convert::TryInto;
use std::hash::Hasher; use std::hash::Hasher;
use std::pin::Pin; use std::pin::Pin;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
pub type ImapNum = usize; pub type ImapNum = usize;
@ -142,7 +143,7 @@ pub struct UIDStore {
msn_index: Arc<Mutex<HashMap<MailboxHash, Vec<UID>>>>, msn_index: Arc<Mutex<HashMap<MailboxHash, Vec<UID>>>>,
byte_cache: Arc<Mutex<HashMap<UID, EnvelopeCache>>>, byte_cache: Arc<Mutex<HashMap<UID, EnvelopeCache>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, collection: Collection,
/* Offline caching */ /* Offline caching */
uidvalidity: Arc<Mutex<HashMap<MailboxHash, UID>>>, uidvalidity: Arc<Mutex<HashMap<MailboxHash, UID>>>,
@ -178,7 +179,7 @@ impl UIDStore {
msn_index: Default::default(), msn_index: Default::default(),
byte_cache: Default::default(), byte_cache: Default::default(),
mailboxes: Arc::new(FutureMutex::new(Default::default())), mailboxes: Arc::new(FutureMutex::new(Default::default())),
tag_index: Arc::new(RwLock::new(Default::default())), collection: Default::default(),
is_online: Arc::new(Mutex::new(( is_online: Arc::new(Mutex::new((
SystemTime::now(), SystemTime::now(),
Err(MeliError::new("Account is uninitialised.")), Err(MeliError::new("Account is uninitialised.")),
@ -710,7 +711,7 @@ impl MailBackend for ImapType {
/* Set flags/tags to true */ /* Set flags/tags to true */
let mut set_seen = false; let mut set_seen = false;
let command = { let command = {
let mut tag_lck = uid_store.tag_index.write().unwrap(); let mut tag_lck = uid_store.collection.tag_index.write().unwrap();
let mut cmd = format!("UID STORE {}", uids[0]); let mut cmd = format!("UID STORE {}", uids[0]);
for uid in uids.iter().skip(1) { for uid in uids.iter().skip(1) {
cmd = format!("{},{}", cmd, uid); cmd = format!("{},{}", cmd, uid);
@ -859,10 +860,6 @@ impl MailBackend for ImapType {
})) }))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {
Some(self.uid_store.tag_index.clone())
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
@ -871,6 +868,10 @@ impl MailBackend for ImapType {
self self
} }
fn collection(&self) -> Collection {
self.uid_store.collection.clone()
}
fn create_mailbox( fn create_mailbox(
&mut self, &mut self,
mut path: String, mut path: String,
@ -1773,7 +1774,7 @@ async fn fetch_hlpr(state: &mut FetchState) -> Result<Vec<Envelope>> {
} }
env.set_references(value); env.set_references(value);
} }
let mut tag_lck = uid_store.tag_index.write().unwrap(); let mut tag_lck = uid_store.collection.tag_index.write().unwrap();
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
env.set_flags(*flags); env.set_flags(*flags);
if !env.is_seen() { if !env.is_seen() {

View File

@ -239,7 +239,7 @@ mod sqlite3_m {
.entry(mailbox_hash) .entry(mailbox_hash)
.and_modify(|entry| *entry = uidvalidity) .and_modify(|entry| *entry = uidvalidity)
.or_insert(uidvalidity); .or_insert(uidvalidity);
let mut tag_lck = self.uid_store.tag_index.write().unwrap(); let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap();
for f in to_str!(&flags).split('\0') { for f in to_str!(&flags).split('\0') {
let hash = tag_hash!(f); let hash = tag_hash!(f);
//debug!("hash {} flag {}", hash, &f); //debug!("hash {} flag {}", hash, &f);

View File

@ -171,7 +171,7 @@ impl ImapConnection {
} }
env.set_references(value); env.set_references(value);
} }
let mut tag_lck = self.uid_store.tag_index.write().unwrap(); let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap();
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
env.set_flags(*flags); env.set_flags(*flags);
if !env.is_seen() { if !env.is_seen() {
@ -469,7 +469,7 @@ impl ImapConnection {
} }
env.set_references(value); env.set_references(value);
} }
let mut tag_lck = self.uid_store.tag_index.write().unwrap(); let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap();
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
env.set_flags(*flags); env.set_flags(*flags);
if !env.is_seen() { if !env.is_seen() {

View File

@ -238,7 +238,7 @@ impl ImapConnection {
} }
env.set_references(value); env.set_references(value);
} }
let mut tag_lck = self.uid_store.tag_index.write().unwrap(); let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap();
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
env.set_flags(*flags); env.set_flags(*flags);
if !env.is_seen() { if !env.is_seen() {
@ -381,7 +381,7 @@ impl ImapConnection {
} }
env.set_references(value); env.set_references(value);
} }
let mut tag_lck = self.uid_store.tag_index.write().unwrap(); let mut tag_lck = self.uid_store.collection.tag_index.write().unwrap();
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
env.set_flags(*flags); env.set_flags(*flags);
if !env.is_seen() { if !env.is_seen() {

View File

@ -388,7 +388,7 @@ pub async fn examine_updates(
} }
env.set_references(value); env.set_references(value);
} }
let mut tag_lck = uid_store.tag_index.write().unwrap(); let mut tag_lck = uid_store.collection.tag_index.write().unwrap();
if let Some((flags, keywords)) = flags { if let Some((flags, keywords)) = flags {
env.set_flags(*flags); env.set_flags(*flags);
if !env.is_seen() { if !env.is_seen() {

View File

@ -23,12 +23,13 @@ use crate::backends::*;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::*; use crate::email::*;
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
use crate::Collection;
use futures::lock::Mutex as FutureMutex; use futures::lock::Mutex as FutureMutex;
use isahc::config::RedirectPolicy; use isahc::config::RedirectPolicy;
use isahc::prelude::HttpClient; use isahc::prelude::HttpClient;
use isahc::ResponseExt; use isahc::ResponseExt;
use serde_json::Value; use serde_json::Value;
use std::collections::{hash_map::DefaultHasher, BTreeMap, HashMap, HashSet}; use std::collections::{hash_map::DefaultHasher, HashMap, HashSet};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::str::FromStr; use std::str::FromStr;
@ -183,7 +184,7 @@ pub struct Store {
pub id_store: Arc<Mutex<HashMap<EnvelopeHash, Id<EmailObject>>>>, pub id_store: Arc<Mutex<HashMap<EnvelopeHash, Id<EmailObject>>>>,
pub reverse_id_store: Arc<Mutex<HashMap<Id<EmailObject>, EnvelopeHash>>>, pub reverse_id_store: Arc<Mutex<HashMap<Id<EmailObject>, EnvelopeHash>>>,
pub blob_id_store: Arc<Mutex<HashMap<EnvelopeHash, Id<BlobObject>>>>, pub blob_id_store: Arc<Mutex<HashMap<EnvelopeHash, Id<BlobObject>>>>,
pub tag_index: Arc<RwLock<BTreeMap<u64, String>>>, pub collection: Collection,
pub mailboxes: Arc<RwLock<HashMap<MailboxHash, JmapMailbox>>>, pub mailboxes: Arc<RwLock<HashMap<MailboxHash, JmapMailbox>>>,
pub mailboxes_index: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>, pub mailboxes_index: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>,
pub mailbox_state: Arc<Mutex<State<MailboxObject>>>, pub mailbox_state: Arc<Mutex<State<MailboxObject>>>,
@ -194,7 +195,7 @@ pub struct Store {
impl Store { impl Store {
pub fn add_envelope(&self, obj: EmailObject) -> Envelope { pub fn add_envelope(&self, obj: EmailObject) -> Envelope {
let mut tag_lck = self.tag_index.write().unwrap(); let mut tag_lck = self.collection.tag_index.write().unwrap();
let tags = obj let tags = obj
.keywords() .keywords()
.keys() .keys()
@ -483,10 +484,6 @@ impl MailBackend for JmapType {
})) }))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {
Some(self.store.tag_index.clone())
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
@ -495,6 +492,10 @@ impl MailBackend for JmapType {
self self
} }
fn collection(&self) -> Collection {
self.store.collection.clone()
}
fn search( fn search(
&self, &self,
q: crate::search::Query, q: crate::search::Query,
@ -753,7 +754,7 @@ impl MailBackend for JmapType {
} }
{ {
let mut tag_index_lck = store.tag_index.write().unwrap(); let mut tag_index_lck = store.collection.tag_index.write().unwrap();
for (flag, value) in flags.iter() { for (flag, value) in flags.iter() {
match flag { match flag {
Ok(_) => {} Ok(_) => {}
@ -841,12 +842,12 @@ impl JmapType {
online_status, online_status,
event_consumer, event_consumer,
is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)), is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)),
collection: Collection::default(),
byte_cache: Default::default(), byte_cache: Default::default(),
id_store: Default::default(), id_store: Default::default(),
reverse_id_store: Default::default(), reverse_id_store: Default::default(),
blob_id_store: Default::default(), blob_id_store: Default::default(),
tag_index: Default::default(),
mailboxes: Default::default(), mailboxes: Default::default(),
mailboxes_index: Default::default(), mailboxes_index: Default::default(),
mailbox_state: Default::default(), mailbox_state: Default::default(),

View File

@ -25,6 +25,7 @@ use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag}; use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{ErrorKind, MeliError, Result}; use crate::error::{ErrorKind, MeliError, Result};
use crate::shellexpand::ShellExpandTrait; use crate::shellexpand::ShellExpandTrait;
use crate::Collection;
use futures::prelude::Stream; use futures::prelude::Stream;
extern crate notify; extern crate notify;
@ -109,6 +110,7 @@ pub struct MaildirType {
mailbox_index: Arc<Mutex<HashMap<EnvelopeHash, MailboxHash>>>, mailbox_index: Arc<Mutex<HashMap<EnvelopeHash, MailboxHash>>>,
hash_indexes: HashIndexes, hash_indexes: HashIndexes,
event_consumer: BackendEventConsumer, event_consumer: BackendEventConsumer,
collection: Collection,
path: PathBuf, path: PathBuf,
} }
@ -1003,6 +1005,10 @@ impl MailBackend for MaildirType {
})) }))
} }
fn collection(&self) -> Collection {
self.collection.clone()
}
fn create_mailbox( fn create_mailbox(
&mut self, &mut self,
new_path: String, new_path: String,
@ -1236,6 +1242,7 @@ impl MaildirType {
hash_indexes: Arc::new(Mutex::new(hash_indexes)), hash_indexes: Arc::new(Mutex::new(hash_indexes)),
mailbox_index: Default::default(), mailbox_index: Default::default(),
event_consumer, event_consumer,
collection: Default::default(),
path: root_path, path: root_path,
})) }))
} }

View File

@ -24,6 +24,7 @@
*/ */
use crate::backends::*; use crate::backends::*;
use crate::collection::Collection;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::parser::BytesExt; use crate::email::parser::BytesExt;
use crate::email::*; use crate::email::*;
@ -708,6 +709,7 @@ impl<'a> Iterator for MessageIterator<'a> {
pub struct MboxType { pub struct MboxType {
account_name: String, account_name: String,
path: PathBuf, path: PathBuf,
collection: Collection,
mailbox_index: Arc<Mutex<HashMap<EnvelopeHash, MailboxHash>>>, mailbox_index: Arc<Mutex<HashMap<EnvelopeHash, MailboxHash>>>,
mailboxes: Arc<Mutex<HashMap<MailboxHash, MboxMailbox>>>, mailboxes: Arc<Mutex<HashMap<MailboxHash, MboxMailbox>>>,
prefer_mbox_type: Option<MboxReader>, prefer_mbox_type: Option<MboxReader>,
@ -1057,6 +1059,10 @@ impl MailBackend for MboxType {
fn as_any_mut(&mut self) -> &mut dyn Any { fn as_any_mut(&mut self) -> &mut dyn Any {
self self
} }
fn collection(&self) -> Collection {
self.collection.clone()
}
} }
macro_rules! get_conf_val { macro_rules! get_conf_val {
@ -1120,6 +1126,7 @@ impl MboxType {
))) )))
} }
}, },
collection: Collection::default(),
mailbox_index: Default::default(), mailbox_index: Default::default(),
mailboxes: Default::default(), mailboxes: Default::default(),
}; };

View File

@ -32,18 +32,18 @@ pub use operations::*;
mod connection; mod connection;
pub use connection::*; pub use connection::*;
use crate::backends::*;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::*; use crate::email::*;
use crate::error::{MeliError, Result, ResultIntoMeliError}; use crate::error::{MeliError, Result, ResultIntoMeliError};
use crate::{backends::*, Collection};
use futures::lock::Mutex as FutureMutex; use futures::lock::Mutex as FutureMutex;
use futures::stream::Stream; use futures::stream::Stream;
use std::collections::{hash_map::DefaultHasher, BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{hash_map::DefaultHasher, BTreeSet, HashMap, HashSet};
use std::future::Future; use std::future::Future;
use std::hash::Hasher; use std::hash::Hasher;
use std::pin::Pin; use std::pin::Pin;
use std::str::FromStr; use std::str::FromStr;
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex};
use std::time::Instant; use std::time::Instant;
pub type UID = usize; pub type UID = usize;
@ -77,6 +77,7 @@ pub struct UIDStore {
hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>, hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>,
uid_index: Arc<Mutex<HashMap<(MailboxHash, UID), EnvelopeHash>>>, uid_index: Arc<Mutex<HashMap<(MailboxHash, UID), EnvelopeHash>>>,
collection: Collection,
mailboxes: Arc<FutureMutex<HashMap<MailboxHash, NntpMailbox>>>, mailboxes: Arc<FutureMutex<HashMap<MailboxHash, NntpMailbox>>>,
is_online: Arc<Mutex<(Instant, Result<()>)>>, is_online: Arc<Mutex<(Instant, Result<()>)>>,
event_consumer: BackendEventConsumer, event_consumer: BackendEventConsumer,
@ -97,6 +98,7 @@ impl UIDStore {
hash_index: Default::default(), hash_index: Default::default(),
uid_index: Default::default(), uid_index: Default::default(),
mailboxes: Arc::new(FutureMutex::new(Default::default())), mailboxes: Arc::new(FutureMutex::new(Default::default())),
collection: Collection::new(),
is_online: Arc::new(Mutex::new(( is_online: Arc::new(Mutex::new((
Instant::now(), Instant::now(),
Err(MeliError::new("Account is uninitialised.")), Err(MeliError::new("Account is uninitialised.")),
@ -294,10 +296,6 @@ impl MailBackend for NntpType {
Err(MeliError::new("NNTP doesn't support deletion.")) Err(MeliError::new("NNTP doesn't support deletion."))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> {
None
}
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
@ -306,6 +304,10 @@ impl MailBackend for NntpType {
self self
} }
fn collection(&self) -> Collection {
self.uid_store.collection.clone()
}
fn create_mailbox( fn create_mailbox(
&mut self, &mut self,
_path: String, _path: String,

View File

@ -19,11 +19,11 @@
* along with meli. If not, see <http://www.gnu.org/licenses/>. * along with meli. If not, see <http://www.gnu.org/licenses/>.
*/ */
use crate::backends::*;
use crate::conf::AccountSettings; use crate::conf::AccountSettings;
use crate::email::{Envelope, EnvelopeHash, Flag}; use crate::email::{Envelope, EnvelopeHash, Flag};
use crate::error::{MeliError, Result}; use crate::error::{MeliError, Result};
use crate::shellexpand::ShellExpandTrait; use crate::shellexpand::ShellExpandTrait;
use crate::{backends::*, Collection};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::collections::{ use std::collections::{
hash_map::{DefaultHasher, HashMap}, hash_map::{DefaultHasher, HashMap},
@ -220,7 +220,7 @@ pub struct NotmuchDb {
mailboxes: Arc<RwLock<HashMap<MailboxHash, NotmuchMailbox>>>, mailboxes: Arc<RwLock<HashMap<MailboxHash, NotmuchMailbox>>>,
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>, index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>,
mailbox_index: Arc<RwLock<HashMap<EnvelopeHash, SmallVec<[MailboxHash; 16]>>>>, mailbox_index: Arc<RwLock<HashMap<EnvelopeHash, SmallVec<[MailboxHash; 16]>>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, collection: Collection,
path: PathBuf, path: PathBuf,
account_name: Arc<String>, account_name: Arc<String>,
account_hash: AccountHash, account_hash: AccountHash,
@ -358,7 +358,7 @@ impl NotmuchDb {
path, path,
index: Arc::new(RwLock::new(Default::default())), index: Arc::new(RwLock::new(Default::default())),
mailbox_index: Arc::new(RwLock::new(Default::default())), mailbox_index: Arc::new(RwLock::new(Default::default())),
tag_index: Arc::new(RwLock::new(Default::default())), collection: Collection::default(),
mailboxes: Arc::new(RwLock::new(mailboxes)), mailboxes: Arc::new(RwLock::new(mailboxes)),
save_messages_to: None, save_messages_to: None,
@ -510,7 +510,7 @@ impl MailBackend for NotmuchDb {
)?); )?);
let index = self.index.clone(); let index = self.index.clone();
let mailbox_index = self.mailbox_index.clone(); let mailbox_index = self.mailbox_index.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.collection.tag_index.clone();
let mailboxes = self.mailboxes.clone(); let mailboxes = self.mailboxes.clone();
let v: Vec<CString>; let v: Vec<CString>;
{ {
@ -561,7 +561,7 @@ impl MailBackend for NotmuchDb {
let mailboxes = self.mailboxes.clone(); let mailboxes = self.mailboxes.clone();
let index = self.index.clone(); let index = self.index.clone();
let mailbox_index = self.mailbox_index.clone(); let mailbox_index = self.mailbox_index.clone();
let tag_index = self.tag_index.clone(); let tag_index = self.collection.tag_index.clone();
let event_consumer = self.event_consumer.clone(); let event_consumer = self.event_consumer.clone();
Ok(Box::pin(async move { Ok(Box::pin(async move {
let new_revision_uuid = database.get_revision_uuid(); let new_revision_uuid = database.get_revision_uuid();
@ -586,13 +586,13 @@ impl MailBackend for NotmuchDb {
use notify::{watcher, RecursiveMode, Watcher}; use notify::{watcher, RecursiveMode, Watcher};
let account_hash = self.account_hash; let account_hash = self.account_hash;
let collection = self.collection.clone();
let lib = self.lib.clone(); let lib = self.lib.clone();
let path = self.path.clone(); let path = self.path.clone();
let revision_uuid = self.revision_uuid.clone(); let revision_uuid = self.revision_uuid.clone();
let mailboxes = self.mailboxes.clone(); let mailboxes = self.mailboxes.clone();
let index = self.index.clone(); let index = self.index.clone();
let mailbox_index = self.mailbox_index.clone(); let mailbox_index = self.mailbox_index.clone();
let tag_index = self.tag_index.clone();
let event_consumer = self.event_consumer.clone(); let event_consumer = self.event_consumer.clone();
let (tx, rx) = std::sync::mpsc::channel(); let (tx, rx) = std::sync::mpsc::channel();
@ -616,7 +616,7 @@ impl MailBackend for NotmuchDb {
mailboxes.clone(), mailboxes.clone(),
index.clone(), index.clone(),
mailbox_index.clone(), mailbox_index.clone(),
tag_index.clone(), collection.tag_index.clone(),
account_hash.clone(), account_hash.clone(),
event_consumer.clone(), event_consumer.clone(),
new_revision_uuid, new_revision_uuid,
@ -651,7 +651,7 @@ impl MailBackend for NotmuchDb {
hash, hash,
index: self.index.clone(), index: self.index.clone(),
bytes: None, bytes: None,
tag_index: self.tag_index.clone(), collection: self.collection.clone(),
})) }))
} }
@ -693,7 +693,7 @@ impl MailBackend for NotmuchDb {
self.lib.clone(), self.lib.clone(),
true, true,
)?; )?;
let tag_index = self.tag_index.clone(); let collection = self.collection.clone();
let index = self.index.clone(); let index = self.index.clone();
Ok(Box::pin(async move { Ok(Box::pin(async move {
@ -781,7 +781,11 @@ impl MailBackend for NotmuchDb {
for (f, v) in flags.iter() { for (f, v) in flags.iter() {
if let (Err(tag), true) = (f, v) { if let (Err(tag), true) = (f, v) {
let hash = tag_hash!(tag); let hash = tag_hash!(tag);
tag_index.write().unwrap().insert(hash, tag.to_string()); collection
.tag_index
.write()
.unwrap()
.insert(hash, tag.to_string());
} }
} }
@ -834,8 +838,8 @@ impl MailBackend for NotmuchDb {
})) }))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn collection(&self) -> Collection {
Some(self.tag_index.clone()) self.collection.clone()
} }
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
@ -851,7 +855,7 @@ impl MailBackend for NotmuchDb {
struct NotmuchOp { struct NotmuchOp {
hash: EnvelopeHash, hash: EnvelopeHash,
index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>, index: Arc<RwLock<HashMap<EnvelopeHash, CString>>>,
tag_index: Arc<RwLock<BTreeMap<u64, String>>>, collection: Collection,
database: Arc<DbConnection>, database: Arc<DbConnection>,
bytes: Option<Vec<u8>>, bytes: Option<Vec<u8>>,
lib: Arc<libloading::Library>, lib: Arc<libloading::Library>,

View File

@ -25,7 +25,7 @@ use smallvec::SmallVec;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::collections::{HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
pub struct EnvelopeRef<'g> { pub struct EnvelopeRef<'g> {
guard: RwLockReadGuard<'g, HashMap<EnvelopeHash, Envelope>>, guard: RwLockReadGuard<'g, HashMap<EnvelopeHash, Envelope>>,
@ -64,8 +64,9 @@ pub struct Collection {
pub envelopes: Arc<RwLock<HashMap<EnvelopeHash, Envelope>>>, pub envelopes: Arc<RwLock<HashMap<EnvelopeHash, Envelope>>>,
pub message_id_index: Arc<RwLock<HashMap<Vec<u8>, EnvelopeHash>>>, pub message_id_index: Arc<RwLock<HashMap<Vec<u8>, EnvelopeHash>>>,
pub threads: Arc<RwLock<HashMap<MailboxHash, Threads>>>, pub threads: Arc<RwLock<HashMap<MailboxHash, Threads>>>,
sent_mailbox: Arc<RwLock<Option<MailboxHash>>>, pub sent_mailbox: Arc<RwLock<Option<MailboxHash>>>,
pub mailboxes: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>, pub mailboxes: Arc<RwLock<HashMap<MailboxHash, HashSet<EnvelopeHash>>>>,
pub tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
} }
impl Default for Collection { impl Default for Collection {
@ -115,6 +116,7 @@ impl Collection {
Collection { Collection {
envelopes: Arc::new(RwLock::new(Default::default())), envelopes: Arc::new(RwLock::new(Default::default())),
tag_index: Arc::new(RwLock::new(BTreeMap::default())),
message_id_index, message_id_index,
threads, threads,
mailboxes, mailboxes,

View File

@ -44,7 +44,6 @@ pub use iterators::*;
use crate::text_processing::grapheme_clusters::*; use crate::text_processing::grapheme_clusters::*;
use uuid::Uuid; use uuid::Uuid;
use std::cell::RefCell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fmt; use std::fmt;
@ -131,7 +130,7 @@ macro_rules! make {
e.parent = Some($p); e.parent = Some($p);
}); });
let old_group = std::mem::replace($threads.groups.entry(old_group_hash).or_default(), ThreadGroup::Node { let old_group = std::mem::replace($threads.groups.entry(old_group_hash).or_default(), ThreadGroup::Node {
parent: RefCell::new(parent_group_hash), parent: Arc::new(RwLock::new(parent_group_hash)),
}); });
$threads.thread_nodes.entry($c).and_modify(|e| { $threads.thread_nodes.entry($c).and_modify(|e| {
e.group = parent_group_hash; e.group = parent_group_hash;
@ -292,7 +291,7 @@ pub struct Thread {
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub enum ThreadGroup { pub enum ThreadGroup {
Root(Thread), Root(Thread),
Node { parent: RefCell<ThreadHash> }, Node { parent: Arc<RwLock<ThreadHash>> },
} }
impl Default for ThreadGroup { impl Default for ThreadGroup {
@ -411,16 +410,16 @@ impl ThreadNode {
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Threads { pub struct Threads {
pub thread_nodes: HashMap<ThreadNodeHash, ThreadNode>, pub thread_nodes: HashMap<ThreadNodeHash, ThreadNode>,
root_set: RefCell<Vec<ThreadNodeHash>>, root_set: Arc<RwLock<Vec<ThreadNodeHash>>>,
tree_index: RefCell<Vec<ThreadNodeHash>>, tree_index: Arc<RwLock<Vec<ThreadNodeHash>>>,
pub groups: HashMap<ThreadHash, ThreadGroup>, pub groups: HashMap<ThreadHash, ThreadGroup>,
message_ids: HashMap<Vec<u8>, ThreadNodeHash>, message_ids: HashMap<Vec<u8>, ThreadNodeHash>,
pub message_ids_set: HashSet<Vec<u8>>, pub message_ids_set: HashSet<Vec<u8>>,
pub missing_message_ids: HashSet<Vec<u8>>, pub missing_message_ids: HashSet<Vec<u8>>,
pub hash_set: HashSet<EnvelopeHash>, pub hash_set: HashSet<EnvelopeHash>,
sort: RefCell<(SortField, SortOrder)>, sort: Arc<RwLock<(SortField, SortOrder)>>,
subsort: RefCell<(SortField, SortOrder)>, subsort: Arc<RwLock<(SortField, SortOrder)>>,
} }
impl PartialEq for ThreadNode { impl PartialEq for ThreadNode {
@ -454,13 +453,13 @@ impl Threads {
pub fn find_group(&self, h: ThreadHash) -> ThreadHash { pub fn find_group(&self, h: ThreadHash) -> ThreadHash {
let p = match self.groups[&h] { let p = match self.groups[&h] {
ThreadGroup::Root(_) => return h, ThreadGroup::Root(_) => return h,
ThreadGroup::Node { ref parent } => *parent.borrow(), ThreadGroup::Node { ref parent } => *parent.read().unwrap(),
}; };
let parent_group = self.find_group(p); let parent_group = self.find_group(p);
match self.groups[&h] { match self.groups[&h] {
ThreadGroup::Node { ref parent } => { ThreadGroup::Node { ref parent } => {
*parent.borrow_mut() = parent_group; *parent.write().unwrap() = parent_group;
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -491,8 +490,8 @@ impl Threads {
message_ids_set, message_ids_set,
missing_message_ids, missing_message_ids,
hash_set, hash_set,
sort: RefCell::new((SortField::Date, SortOrder::Desc)), sort: Arc::new(RwLock::new((SortField::Date, SortOrder::Desc))),
subsort: RefCell::new((SortField::Subject, SortOrder::Desc)), subsort: Arc::new(RwLock::new((SortField::Subject, SortOrder::Desc))),
..Default::default() ..Default::default()
} }
@ -573,7 +572,7 @@ impl Threads {
}; };
if self.thread_nodes[&t_id].parent.is_none() { if self.thread_nodes[&t_id].parent.is_none() {
let mut tree_index = self.tree_index.borrow_mut(); let mut tree_index = self.tree_index.write().unwrap();
if let Some(i) = tree_index.iter().position(|t| *t == t_id) { if let Some(i) = tree_index.iter().position(|t| *t == t_id) {
tree_index.remove(i); tree_index.remove(i);
} }
@ -845,7 +844,7 @@ impl Threads {
/* /*
save_graph( save_graph(
&self.tree_index.borrow(), &self.tree_index.read().unwrap(),
&self.thread_nodes, &self.thread_nodes,
&self &self
.message_ids .message_ids
@ -871,7 +870,7 @@ impl Threads {
ref thread_nodes, ref thread_nodes,
.. ..
} = self; } = self;
let tree = &mut tree_index.borrow_mut(); let tree = &mut tree_index.write().unwrap();
for t in tree.iter_mut() { for t in tree.iter_mut() {
thread_nodes[t].children.sort_by(|a, b| match subsort { thread_nodes[t].children.sort_by(|a, b| match subsort {
(SortField::Date, SortOrder::Desc) => { (SortField::Date, SortOrder::Desc) => {
@ -1090,7 +1089,7 @@ impl Threads {
}); });
} }
fn inner_sort_by(&self, sort: (SortField, SortOrder), envelopes: &Envelopes) { fn inner_sort_by(&self, sort: (SortField, SortOrder), envelopes: &Envelopes) {
let tree = &mut self.tree_index.borrow_mut(); let tree = &mut self.tree_index.write().unwrap();
let envelopes = envelopes.read().unwrap(); let envelopes = envelopes.read().unwrap();
tree.sort_by(|a, b| match sort { tree.sort_by(|a, b| match sort {
(SortField::Date, SortOrder::Desc) => { (SortField::Date, SortOrder::Desc) => {
@ -1172,13 +1171,13 @@ impl Threads {
subsort: (SortField, SortOrder), subsort: (SortField, SortOrder),
envelopes: &Envelopes, envelopes: &Envelopes,
) { ) {
if *self.sort.borrow() != sort { if *self.sort.read().unwrap() != sort {
self.inner_sort_by(sort, envelopes); self.inner_sort_by(sort, envelopes);
*self.sort.borrow_mut() = sort; *self.sort.write().unwrap() = sort;
} }
if *self.subsort.borrow() != subsort { if *self.subsort.read().unwrap() != subsort {
self.inner_subsort_by(subsort, envelopes); self.inner_subsort_by(subsort, envelopes);
*self.subsort.borrow_mut() = subsort; *self.subsort.write().unwrap() = subsort;
} }
} }
@ -1196,11 +1195,11 @@ impl Threads {
} }
pub fn root_len(&self) -> usize { pub fn root_len(&self) -> usize {
self.tree_index.borrow().len() self.tree_index.read().unwrap().len()
} }
pub fn root_set(&self, idx: usize) -> ThreadNodeHash { pub fn root_set(&self, idx: usize) -> ThreadNodeHash {
self.tree_index.borrow()[idx] self.tree_index.read().unwrap()[idx]
} }
pub fn roots(&self) -> SmallVec<[ThreadHash; 1024]> { pub fn roots(&self) -> SmallVec<[ThreadHash; 1024]> {

View File

@ -895,9 +895,9 @@ impl CompactListing {
let thread = threads.thread_ref(hash); let thread = threads.thread_ref(hash);
let mut tags = String::new(); let mut tags = String::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::new(); let mut colors: SmallVec<[_; 8]> = SmallVec::new();
let backend_lck = context.accounts[&self.cursor_pos.0].backend.read().unwrap(); let account = &context.accounts[&self.cursor_pos.0];
if let Some(t) = backend_lck.tags() { if account.backend_capabilities.supports_tags {
let tags_lck = t.read().unwrap(); let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if mailbox_settings!( if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1] context[self.cursor_pos.0][&self.cursor_pos.1]

View File

@ -908,9 +908,9 @@ impl ConversationsListing {
let thread = threads.thread_ref(hash); let thread = threads.thread_ref(hash);
let mut tags = String::new(); let mut tags = String::new();
let mut colors = SmallVec::new(); let mut colors = SmallVec::new();
let backend_lck = context.accounts[&self.cursor_pos.0].backend.read().unwrap(); let account = &context.accounts[&self.cursor_pos.0];
if let Some(t) = backend_lck.tags() { if account.backend_capabilities.supports_tags {
let tags_lck = t.read().unwrap(); let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if mailbox_settings!( if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1] context[self.cursor_pos.0][&self.cursor_pos.1]

View File

@ -732,9 +732,9 @@ impl PlainListing {
fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings { fn make_entry_string(&self, e: EnvelopeRef, context: &Context) -> EntryStrings {
let mut tags = String::new(); let mut tags = String::new();
let mut colors = SmallVec::new(); let mut colors = SmallVec::new();
let backend_lck = context.accounts[&self.cursor_pos.0].backend.read().unwrap(); let account = &context.accounts[&self.cursor_pos.0];
if let Some(t) = backend_lck.tags() { if account.backend_capabilities.supports_tags {
let tags_lck = t.read().unwrap(); let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if mailbox_settings!( if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1] context[self.cursor_pos.0][&self.cursor_pos.1]

View File

@ -839,9 +839,9 @@ impl ThreadListing {
fn make_entry_string(&self, e: &Envelope, context: &Context) -> EntryStrings { fn make_entry_string(&self, e: &Envelope, context: &Context) -> EntryStrings {
let mut tags = String::new(); let mut tags = String::new();
let mut colors: SmallVec<[_; 8]> = SmallVec::new(); let mut colors: SmallVec<[_; 8]> = SmallVec::new();
let backend_lck = context.accounts[&self.cursor_pos.0].backend.read().unwrap(); let account = &context.accounts[&self.cursor_pos.0];
if let Some(t) = backend_lck.tags() { if account.backend_capabilities.supports_tags {
let tags_lck = t.read().unwrap(); let tags_lck = account.collection.tag_index.read().unwrap();
for t in e.labels().iter() { for t in e.labels().iter() {
if mailbox_settings!( if mailbox_settings!(
context[self.cursor_pos.0][&self.cursor_pos.1] context[self.cursor_pos.0][&self.cursor_pos.1]

View File

@ -517,7 +517,7 @@ impl Account {
tree: Default::default(), tree: Default::default(),
address_book, address_book,
sent_mailbox: Default::default(), sent_mailbox: Default::default(),
collection: Default::default(), collection: backend.collection(),
settings, settings,
sender, sender,
job_executor, job_executor,

View File

@ -46,7 +46,7 @@ pub struct PluginBackend {
plugin: Plugin, plugin: Plugin,
child: std::process::Child, child: std::process::Child,
channel: Arc<Mutex<RpcChannel>>, channel: Arc<Mutex<RpcChannel>>,
tag_index: Option<Arc<RwLock<BTreeMap<u64, String>>>>, collection: melib::Collection,
is_online: Arc<Mutex<(std::time::Instant, Result<()>)>>, is_online: Arc<Mutex<(std::time::Instant, Result<()>)>>,
} }
@ -200,7 +200,6 @@ impl MailBackend for PluginBackend {
Ok(Box::new(PluginOp { Ok(Box::new(PluginOp {
hash, hash,
channel: self.channel.clone(), channel: self.channel.clone(),
tag_index: self.tag_index.clone(),
bytes: None, bytes: None,
})) }))
} }
@ -219,8 +218,8 @@ impl MailBackend for PluginBackend {
) -> ResultFuture<(MailboxHash, HashMap<MailboxHash, Mailbox>)> { ) -> ResultFuture<(MailboxHash, HashMap<MailboxHash, Mailbox>)> {
Err(MeliError::new("Unimplemented.")) Err(MeliError::new("Unimplemented."))
} }
fn tags(&self) -> Option<Arc<RwLock<BTreeMap<u64, String>>>> { fn collection(&self) -> melib::Collection {
self.tag_index.clone() self.collection.clone()
} }
fn as_any(&self) -> &dyn ::std::any::Any { fn as_any(&self) -> &dyn ::std::any::Any {
self self
@ -257,7 +256,7 @@ impl PluginBackend {
child, child,
plugin, plugin,
channel: Arc::new(Mutex::new(channel)), channel: Arc::new(Mutex::new(channel)),
tag_index: None, collection: Default::default(),
is_online: Arc::new(Mutex::new((now, Err(MeliError::new("Unitialized"))))), is_online: Arc::new(Mutex::new((now, Err(MeliError::new("Unitialized"))))),
})) }))
} }
@ -285,7 +284,6 @@ impl PluginBackend {
struct PluginOp { struct PluginOp {
hash: EnvelopeHash, hash: EnvelopeHash,
channel: Arc<Mutex<RpcChannel>>, channel: Arc<Mutex<RpcChannel>>,
tag_index: Option<Arc<RwLock<BTreeMap<u64, String>>>>,
bytes: Option<String>, bytes: Option<String>,
} }